gtk4-query-settings.xml \
gtk4-update-icon-cache.xml \
input-handling.xml \
- migrating-2to3.xml \
- migrating-3xtoy.xml \
- migrating-checklist.sgml \
- migrating-GtkGrid.xml \
- migrating-GtkStyleContext.xml \
- migrating-smclient-GtkApplication.xml \
- migrating-unique-GtkApplication.xml \
+ migrating-2to4.xml \
+ migrating-3to4.xml \
mir.xml \
osx.sgml \
overview.xml \
getting_started.xml \
glossary.xml \
input-handling.xml \
- migrating-2to3.xml \
- migrating-3xtoy.xml \
- migrating-checklist.sgml \
- migrating-GtkGrid.xml \
- migrating-GtkStyleContext.xml \
- migrating-smclient-GtkApplication.xml \
- migrating-unique-GtkApplication.xml \
+ migrating-2to4.xml \
+ migrating-3to4.xml \
question_index.sgml \
text_widget.sgml \
tree_widget.sgml
</para>
</partintro>
- <xi:include href="xml/migrating-2to3.xml" />
- <xi:include href="xml/migrating-GtkStyleContext.xml" />
- <xi:include href="xml/migrating-unique-GtkApplication.xml" />
- <xi:include href="xml/migrating-smclient-GtkApplication.xml" />
- <xi:include href="xml/migrating-GtkGrid.xml" />
- <xi:include href="xml/migrating-checklist.sgml" />
- <xi:include href="xml/migrating-3xtoy.xml" />
+ <xi:include href="xml/migrating-2to4.xml" />
+ <xi:include href="xml/migrating-3to4.xml" />
</part>
<part>
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
-]>
-<chapter id="gtk-migrating-2-to-3">
- <title>Migrating from GTK+ 2.x to GTK+ 3</title>
-
- <para>
- GTK+ 3 is a major new version of GTK+ that breaks both API and ABI
- compared to GTK+ 2.x, which has remained API- and ABI-stable for a
- long time. Thankfully, most of the changes are not hard to adapt to
- and there are a number of steps that you can take to prepare your
- GTK+ 2.x application for the switch to GTK+ 3. After that, there's
- a small number of adjustments that you may have to do when you actually
- switch your application to build against GTK+ 3.
- </para>
-
- <section>
- <title>Preparation in GTK+ 2.x</title>
-
- <para>
- The steps outlined in the following sections assume that your
- application is working with GTK+ 2.24, which is the final stable
- release of GTK+ 2.x. It includes all the necessary APIs and tools
- to help you port your application to GTK+ 3. If you are still using
- an older version of GTK+ 2.x, you should first get your application
- to build and work with 2.24.
- </para>
-
- <section>
- <title>Do not include individual headers</title>
- <para>
- With GTK+ 2.x it was common to include just the header files for
- a few widgets that your application was using, which could lead
- to problems with missing definitions, etc. GTK+ 3 tightens the
- rules about which header files you are allowed to include directly.
- The allowed header files are are
- <variablelist>
- <varlistentry>
- <term><filename>gtk/gtk.h</filename></term>
- <listitem>for GTK</listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>gtk/gtkx.h</filename></term>
- <listitem>for the X-specfic widgets #GtkSocket and #GtkPlug</listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>gtk/gtkunixprint.h</filename></term>
- <listitem>for low-level, UNIX-specific printing functions</listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>gdk/gdk.h</filename></term>
- <listitem>for GDK</listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>gdk/gdkx.h</filename></term>
- <listitem>for GDK functions that are X11-specific</listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>gdk/gdkwin32.h</filename></term>
- <listitem>for GDK functions that are Windows-specific</listitem>
- </varlistentry>
- </variablelist>
- (these relative paths are assuming that you are using the include
- paths that are specified in the gtk+-2.0.pc file, as returned by
- <literal>pkg-config --cflags gtk+-2.0.pc</literal>.)
- </para>
- <para>
- To check that your application only includes the allowed headers,
- you can use defines to disable inclusion of individual headers,
- as follows:
- <programlisting>
- make CFLAGS+="-DGTK_DISABLE_SINGLE_INCLUDES"
- </programlisting>
- </para>
- </section>
-
- <section>
- <title>Do not use deprecated symbols</title>
- <para>
- Over the years, a number of functions, and in some cases, entire
- widgets have been deprecated. These deprecations are clearly spelled
- out in the API reference, with hints about the recommended replacements.
- The API reference for GTK+ 2 also includes an
- <ulink url="https://developer.gnome.org/gtk2/2.24/api-index-deprecated.html">index</ulink> of all deprecated symbols.
- </para>
- <para>
- To verify that your program does not use any deprecated symbols,
- you can use defines to remove deprecated symbols from the header files,
- as follows:
- <programlisting>
- make CFLAGS+="-DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED"
- </programlisting>
- </para>
- <para>
- Note that some parts of our API, such as enumeration values, are
- not well covered by the deprecation warnings. In most cases, using
- them will require you to also use deprecated functions, which will
- trigger warnings. But some things, like the %GTK_DIALOG_NO_SEPARATOR
- flag that has disappeared in GTK+ 3, may not.
- </para>
- </section>
-
- <section>
- <title>Use accessor functions instead of direct access</title>
- <para>
- GTK+ 3 removes many implementation details and struct members from
- its public headers.
- </para>
- <para>
- To ensure that your application does not have problems with this, you
- define the preprocessor symbol <literal>GSEAL_ENABLE</literal> while
- building your application against GTK+ 2.x. This will make the compiler
- catch all uses of direct access to struct fields so that you can go
- through them one by one and replace them with a call to an accessor
- function instead.
- <programlisting>
- make CFLAGS+="-DGSEAL_ENABLE"
- </programlisting>
- </para>
- <para>
- While it may be painful to convert, this helps us keep API and ABI
- compatibility when we change internal interfaces. As a quick example,
- when adding GSEAL_ENABLE, if you see an error like:
- <programlisting>
- error: 'GtkToggleButton' has no member named 'active'
- </programlisting>
- this means that you are accessing the public structure of
- GtkToggleButton directly, perhaps with some code like:
- <informalexample><programlisting>
- static void
- on_toggled (GtkToggleButton *button)
- {
- if (button->active)
- frob_active ();
- else
- frob_inactive ();
- }
- </programlisting></informalexample>
- </para>
- <para>
- In most cases, this can easily be replaced with the correct accessor
- method. The main rule is that if you have code like the above which
- accesses the "active" field of a "GtkToggleButton", then the accessor
- method becomes "gtk_toggle_button_get_active":
- <informalexample><programlisting>
- static void
- on_toggled (GtkToggleButton *button)
- {
- if (gtk_toggle_button_get_active (button))
- frob_active ();
- else
- frob_inactive ();
- }
- </programlisting></informalexample>
- </para>
- <para>
- In the case of setting field members directly, there's usually
- a corresponding setter method.
- </para>
- </section>
-
- <section>
- <title>Replace GDK_<keyname> with GDK_KEY_<keyname></title>
-
- <para>
- Key constants have gained a <literal>_KEY_</literal> infix.
- For example, <literal>GDK_a</literal> is now
- <literal>GDK_KEY_a</literal>. In GTK+ 2, the old names continue
- to be available. In GTK+ 3 however, the old names will require
- an explicit include of the <literal>gdkkeysyms-compat.h</literal> header.
- </para>
-
- </section>
-
- <section>
- <title>Use GIO for launching applications</title>
- <para>
- The <literal>gdk_spawn</literal> family of functions has been
- deprecated in GDK 2.24 and removed from GDK 3. Various replacements
- exist; the best replacement depends on the circumstances:
- <itemizedlist>
- <listitem>If you are opening a document or URI by launching a command
- like <literal>firefox http://my-favourite-website.com</literal> or
- <literal>gnome-open ghelp:epiphany</literal>, it is best to just use
- gtk_show_uri(); as an added benefit, your application will henceforth
- respect the users preference for what application to use.</listitem>
- <listitem>If you are launching a regular, installed application that
- has a desktop file, it is best to use GIOs #GAppInfo with a suitable
- launch context.
- <informalexample><programlisting>
- GAppInfo *info;
- GAppLaunchContext *context;
- GError *error = NULL;
-
- info = (GAppInfo*) g_desktop_app_info_new ("epiphany.desktop");
- context = (GAppLaunchContext*) gdk_display_get_app_launch_context (display);
- g_app_info_launch (info, NULL, context, &error);
-
- if (error)
- {
- g_warning ("Failed to launch epiphany: %s", error->message);
- g_error_free (error);
- }
-
- g_object_unref (info);
- g_object_unref (context);
- </programlisting></informalexample>
- Remember that you have to include
- <filename>gio/gdesktopappinfo.h</filename>
- and use the <filename>gio-unix-2.0</filename> pkg-config file
- when using g_desktop_app_info_new().
- </listitem>
- <listitem>If you are launching a custom commandline, you can
- still use g_app_info_launch() with a GAppInfo that is constructed
- with g_app_info_create_from_commandline(), or you can use the
- more lowlevel <literal>g_spawn</literal> family of functions
- (e.g. g_spawn_command_line_async()), and pass <envar>DISPLAY</envar>
- in the environment. gdk_screen_make_display_name() can be
- used to find the right value for the <envar>DISPLAY</envar>
- environment variable.
- </listitem>
- </itemizedlist>
- </para>
- </section>
-
- <section>
- <title>Use cairo for drawing</title>
- <para>
- In GTK+ 3, the GDK drawing API (which closely mimics the X
- drawing API, which is itself modeled after PostScript) has been
- removed. All drawing in GTK+ 3 is done via cairo.
- </para>
- <para>
- The #GdkGC and #GdkImage objects, as well as all the functions using
- them, are gone. This includes the <literal>gdk_draw</literal> family
- of functions like gdk_draw_rectangle() and gdk_draw_drawable(). As
- #GdkGC is roughly equivalent to #cairo_t and #GdkImage was used for
- drawing images to GdkWindows, which cairo supports automatically,
- a transition is usually straightforward.
- </para>
- <para>
- The following examples show a few common drawing idioms used by
- applications that have been ported to use cairo and how the code
- was replaced.
- </para>
- <example>
- <title>Drawing a GdkPixbuf onto a GdkWindow</title>
- <para>
- Drawing a pixbuf onto a drawable used to be done like this:
- <informalexample><programlisting>
-gdk_draw_pixbuf (window,
- gtk_widget_get_style (widget)->black_gc,
- pixbuf,
- 0, 0
- x, y,
- gdk_pixbuf_get_width (pixbuf),
- gdk_pixbuf_get_height (pixbuf),
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
- </programlisting></informalexample>
- Doing the same thing with cairo:
- <informalexample><programlisting>
-cairo_t *cr = gdk_cairo_create (window);
-gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
-cairo_paint (cr);
-cairo_destroy (cr);
- </programlisting></informalexample>
- Note that very similar code can be used when porting code
- using GdkPixmap to #cairo_surface_t by calling
- cairo_set_source_surface() instead of
- gdk_cairo_set_source_pixbuf().
- </para>
- </example>
- <example>
- <title>Drawing a tiled GdkPixmap to a GdkWindow</title>
- <para>
- Tiled pixmaps are often used for drawing backgrounds.
- Old code looked something like this:
- <informalexample><programlisting>
-GdkGCValues gc_values;
-GdkGC *gc;
-
-/* setup */
-gc = gtk_widget_get_style (widget)->black_gc;
-gdk_gc_set_tile (gc, pixmap);
-gdk_gc_set_fill (gc, GDK_TILED);
-gdk_gc_set_ts_origin (gc, x_origin, y_origin);
-/* use */
-gdk_draw_rectangle (window, gc, TRUE, 0, 0, width, height);
-/* restore */
-gdk_gc_set_tile (gc, NULL);
-gdk_gc_set_fill (gc, GDK_SOLID);
-gdk_gc_set_ts_origin (gc, 0, 0);
- </programlisting></informalexample>
- The equivalent cairo code to draw a tiled surface looks
- like this:
- <informalexample><programlisting>
-cairo_t *cr;
-cairo_surface_t *surface;
-
-surface = ...
-cr = gdk_cairo_create (window);
-cairo_set_source_surface (cr, surface, x_origin, y_origin);
-cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
-cairo_rectangle (cr, 0, 0, width, height);
-cairo_fill (cr);
-cairo_destroy (cr);
- </programlisting></informalexample>
-The surface here can be either an image surface or a X surface,
-and can either be created on the spot or kept around for caching purposes.
-Another alternative is to use pixbufs instead of surfaces with
-gdk_cairo_set_source_pixbuf() instead of cairo_set_source_surface().
- </para>
- </example>
- <example>
- <title>Drawing a PangoLayout to a clipped area</title>
- <para>
- Drawing layouts clipped is often used to avoid overdraw or to
- allow drawing selections. Code would have looked like this:
- <informalexample><programlisting>
-GdkGC *gc;
-
-/* setup */
-gc = gtk_widget_get_style (widget)->text_gc[state];
-gdk_gc_set_clip_rectangle (gc, &area);
-/* use */
-gdk_draw_layout (drawable, gc, x, y, layout);
-/* restore */
-gdk_gc_set_clip_rectangle (gc, NULL);
- </programlisting></informalexample>
- With cairo, the same effect can be achieved using:
- <informalexample><programlisting>
-GtkStyleContext *context;
-GtkStateFlags flags;
-GdkRGBA rgba;
-cairo_t *cr;
-
-cr = gdk_cairo_create (drawable);
-/* clip */
-gdk_cairo_rectangle (cr, &area);
-cairo_clip (cr);
-/* set the correct source color */
-context = gtk_widget_get_style_context (widget));
-state = gtk_widget_get_state_flags (widget);
-gtk_style_context_get_color (context, state, &rgba);
-gdk_cairo_set_source_rgba (cr, &rgba);
-/* draw the text */
-cairo_move_to (cr, x, y);
-pango_cairo_show_layout (cr, layout);
-cairo_destroy (cr);
- </programlisting></informalexample>
- Clipping using cairo_clip() is of course not restricted to text
- rendering and can be used everywhere where GC clips were used.
- And using gdk_cairo_set_source_color() with style colors should
- be used in all the places where a style’s GC was used to achieve
- a particular color.
- </para>
- </example>
- <section>
- <title>What should you be aware of ?</title>
- <formalpara><title>No more stippling</title>
- <para>
- Stippling is the usage of a bi-level mask, called a #GdkBitmap.
- It was often used to achieve a checkerboard effect. You can use
- cairo_mask() to achieve this effect. To get a checkerbox mask,
- you can use code like this:
- <informalexample><programlisting>
-static cairo_pattern_t *
-gtk_color_button_get_checkered (void)
-{
- /* need to respect pixman's stride being a multiple of 4 */
- static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0xFF, 0x00, 0x00 };
- cairo_surface_t *surface;
- cairo_pattern_t *pattern;
-
- surface = cairo_image_surface_create_for_data (data,
- CAIRO_FORMAT_A8,
- 2, 2,
- 4);
- pattern = cairo_pattern_create_for_surface (surface);
- cairo_surface_destroy (surface);
- cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
- cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
-
- return pattern;
-}
- </programlisting></informalexample>
- Note that stippling looks very outdated in UIs, and is rarely
- used in modern applications. All properties that made use of
- stippling have been removed from GTK+ 3. Most prominently,
- stippling is absent from text rendering, in particular #GtkTextTag.
- </para>
- </formalpara>
- <formalpara><title>Using the target also as source or mask</title>
- <para>
- The gdk_draw_drawable() function allowed using the same drawable
- as source and target. This was often used to achieve a scrolling
- effect. Cairo does not allow this yet. You can however use
- cairo_push_group() to get a different intermediate target that
- you can copy to. So you can replace this code:
- <informalexample><programlisting>
-gdk_draw_drawable (pixmap,
- gc,
- pixmap,
- area.x + dx, area.y + dy,
- area.x, area.y,
- area.width, area.height);
- </programlisting></informalexample>
- By using this code:
- <informalexample><programlisting>
-cairo_t *cr = cairo_create (surface);
-/* clipping restricts the intermediate surface's size, so it's a good idea
- * to use it. */
-gdk_cairo_rectangle (cr, &area);
-cairo_clip (cr);
-/* Now push a group to change the target */
-cairo_push_group (cr);
-cairo_set_source_surface (cr, surface, dx, dy);
-cairo_paint (cr);
-/* Now copy the intermediate target back */
-cairo_pop_group_to_source (cr);
-cairo_paint (cr);
-cairo_destroy (cr);
- </programlisting></informalexample>
-The surface here can be either an image surface or a X surface,
-and can either be created on the spot or kept around for caching purposes.
-Another alternative is to use pixbufs instead of surfaces with
-gdk_cairo_set_source_pixbuf() instead of cairo_set_source_surface().
- </para>
- <para>
- The cairo developers plan to add self-copies in the future to allow
- exactly this effect, so you might want to keep up on cairo
- development to be able to change your code.
- </para>
- </formalpara>
- <formalpara><title>Using pango_cairo_show_layout(<!-- -->) instead of gdk_draw_layout_with_colors(<!-- -->)</title>
- <para>
- GDK provided a way to ignore the color attributes of text and use
- a hardcoded text color with the gdk_draw_layout_with_colors()
- function. This is often used to draw text shadows or selections.
- Pango’s cairo support does not yet provide this functionality. If
- you use Pango layouts that change colors, the easiest way to achieve
- a similar effect is using pango_cairo_layout_path() and cairo_fill()
- instead of gdk_draw_layout_with_colors(). Note that this results in
- a slightly uglier-looking text, as subpixel anti-aliasing is not
- supported.
- </para>
- </formalpara>
- </section>
- </section>
- </section>
-
- <section>
- <title>Changes that need to be done at the time of the switch</title>
-
- <para>
- This section outlines porting tasks that you need to tackle when
- you get to the point that you actually build your application against
- GTK+ 3. Making it possible to prepare for these in GTK+ 2.24 would
- have been either impossible or impractical.
- </para>
-
- <section>
- <title>Replace size_request by get_preferred_width/height</title>
-
- <para>
- The request-phase of the traditional GTK+ geometry management
- has been replaced by a more flexible height-for-width system,
- which is described in detail in the API documentation
- (see <xref linkend="geometry-management"/>). As a consequence,
- the ::size-request signal and vfunc has been removed from
- #GtkWidgetClass. The replacement for size_request() can
- take several levels of sophistication:
- <itemizedlist>
- <listitem>
- <para>
- As a minimal replacement to keep current functionality,
- you can simply implement the #GtkWidgetClass.get_preferred_width() and
- #GtkWidgetClass.get_preferred_height() vfuncs by calling your existing
- size_request() function. So you go from
- <informalexample><programlisting>
-static void
-my_widget_class_init (MyWidgetClass *class)
-{
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
-
- /* ... */
-
- widget_class->size_request = my_widget_size_request;
-
- /* ... */
-}
- </programlisting></informalexample>
- <para>
- to something that looks more like this:
- </para>
- <informalexample><programlisting>
-static void
-my_widget_get_preferred_width (GtkWidget *widget,
- gint *minimal_width,
- gint *natural_width)
-{
- GtkRequisition requisition;
-
- my_widget_size_request (widget, &requisition);
-
- *minimal_width = *natural_width = requisition.width;
-}
-
-static void
-my_widget_get_preferred_height (GtkWidget *widget,
- gint *minimal_height,
- gint *natural_height)
-{
- GtkRequisition requisition;
-
- my_widget_size_request (widget, &requisition);
-
- *minimal_height = *natural_height = requisition.height;
-}
-
- /* ... */
-
-static void
-my_widget_class_init (MyWidgetClass *class)
-{
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
-
- /* ... */
-
- widget_class->get_preferred_width = my_widget_get_preferred_width;
- widget_class->get_preferred_height = my_widget_get_preferred_height;
-
- /* ... */
-
-}
- </programlisting></informalexample>
- <para>
- Sometimes you can make things a little more streamlined
- by replacing your existing size_request() implementation by
- one that takes an orientation parameter:
- </para>
- <informalexample><programlisting>
-static void
-my_widget_get_preferred_size (GtkWidget *widget,
- GtkOrientation orientation,
- gint *minimal_size,
- gint *natural_size)
-{
-
- /* do things that are common for both orientations ... */
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- /* do stuff that only applies to width... */
-
- *minimal_size = *natural_size = ...
- }
- else
- {
- /* do stuff that only applies to height... */
-
- *minimal_size = *natural_size = ...
- }
-}
-
-static void
-my_widget_get_preferred_width (GtkWidget *widget,
- gint *minimal_width,
- gint *natural_width)
-{
- my_widget_get_preferred_size (widget,
- GTK_ORIENTATION_HORIZONTAL,
- minimal_width,
- natural_width);
-}
-
-static void
-my_widget_get_preferred_height (GtkWidget *widget,
- gint *minimal_height,
- gint *natural_height)
-{
- my_widget_get_preferred_size (widget,
- GTK_ORIENTATION_VERTICAL,
- minimal_height,
- natural_height);
-}
-
- /* ... */
- </programlisting></informalexample>
- </para>
- </listitem>
- <listitem>
- <para>If your widget can cope with a small size,
- but would appreciate getting some more space (a common
- example would be that it contains ellipsizable labels),
- you can do that by making your #GtkWidgetClass.get_preferred_width() /
- #GtkWidgetClass.get_preferred_height()
- functions return a smaller value for @minimal than for @natural.
- For @minimal, you probably want to return the same value
- that your size_request() function returned before (since
- size_request() was defined as returning the minimal size
- a widget can work with). A simple way to obtain good
- values for @natural, in the case of containers, is to use
- gtk_widget_get_preferred_width() and
- gtk_widget_get_preferred_height() on the children of the
- container, as in the following example:
- <informalexample><programlisting>
-static void
-gtk_fixed_get_preferred_height (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- GtkFixed *fixed = GTK_FIXED (widget);
- GtkFixedPrivate *priv = fixed->priv;
- GtkFixedChild *child;
- GList *children;
- gint child_min, child_nat;
-
- *minimum = 0;
- *natural = 0;
-
- for (children = priv->children; children; children = children->next)
- {
- child = children->data;
-
- if (!gtk_widget_get_visible (child->widget))
- continue;
-
- gtk_widget_get_preferred_height (child->widget, &child_min, &child_nat);
-
- *minimum = MAX (*minimum, child->y + child_min);
- *natural = MAX (*natural, child->y + child_nat);
- }
-}
- </programlisting></informalexample>
- </para>
- </listitem>
- <listitem>
- <para>
- Note that the #GtkWidgetClass.get_preferred_width() /
- #GtkWidgetClass.get_preferred_height() functions
- only allow you to deal with one dimension at a time. If your
- size_request() handler is doing things that involve both
- width and height at the same time (e.g. limiting the aspect
- ratio), you will have to implement
- #GtkWidgetClass.get_preferred_height_for_width()
- and #GtkWidgetClass.get_preferred_width_for_height().
- </para>
- </listitem>
- <listitem>
- <para>
- To make full use of the new capabilities of the
- height-for-width geometry management, you need to additionally
- implement the #GtkWidgetClass.get_preferred_height_for_width() and
- #GtkWidgetClass.get_preferred_width_for_height(). For details on
- these functions, see <xref linkend="geometry-management"/>.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
-
- <section>
- <title>Replace GdkRegion by cairo_region_t</title>
-
- <para>
- Starting with version 1.10, cairo provides a region API that is
- equivalent to the GDK region API (which was itself copied from
- the X server). Therefore, the region API has been removed in GTK+ 3.
- </para>
- <para>
- Porting your application to the cairo region API should be a straight
- find-and-replace task. Please refer to the following table:
- <table>
- <tgroup cols="2">
- <title>GdkRegion to cairo_region_t</title>
- <thead>
- <row><entry>GDK</entry><entry>cairo</entry></row>
- </thead>
- <tbody>
- <row><entry>#GdkRegion</entry><entry>#cairo_region_t</entry></row>
- <row><entry>#GdkRectangle</entry><entry>#cairo_rectangle_int_t</entry></row>
- <row><entry>gdk_rectangle_intersect()</entry><entry>this function is still there</entry></row>
- <row><entry>gdk_rectangle_union()</entry><entry>this function is still there</entry></row>
- <row><entry>gdk_region_new()</entry><entry>cairo_region_create()</entry></row>
- <row><entry>gdk_region_copy()</entry><entry>cairo_region_copy()</entry></row>
- <row><entry>gdk_region_destroy()</entry><entry>cairo_region_destroy()</entry></row>
- <row><entry>gdk_region_rectangle()</entry><entry>cairo_region_create_rectangle()</entry></row>
- <row><entry>gdk_region_get_clipbox()</entry><entry>cairo_region_get_extents()</entry></row>
- <row><entry>gdk_region_get_rectangles()</entry><entry>cairo_region_num_rectangles() and
- cairo_region_get_rectangle()</entry></row>
- <row><entry>gdk_region_empty()</entry><entry>cairo_region_is_empty()</entry></row>
- <row><entry>gdk_region_equal()</entry><entry>cairo_region_equal()</entry></row>
- <row><entry>gdk_region_point_in()</entry><entry>cairo_region_contains_point()</entry></row>
- <row><entry>gdk_region_rect_in()</entry><entry>cairo_region_contains_rectangle()</entry></row>
- <row><entry>gdk_region_offset()</entry><entry>cairo_region_translate()</entry></row>
- <row><entry>gdk_region_union_with_rect()</entry><entry>cairo_region_union_rectangle()</entry></row>
- <row><entry>gdk_region_intersect()</entry><entry>cairo_region_intersect()</entry></row>
- <row><entry>gdk_region_union()</entry><entry>cairo_region_union()</entry></row>
- <row><entry>gdk_region_subtract()</entry><entry>cairo_region_subtract()</entry></row>
- <row><entry>gdk_region_xor()</entry><entry>cairo_region_xor()</entry></row>
- <row><entry>gdk_region_shrink()</entry><entry>no replacement</entry></row>
- <row><entry>gdk_region_polygon()</entry><entry>no replacement, use cairo paths instead</entry></row>
- </tbody>
- </tgroup>
- </table>
- </para>
- </section>
-
- <section>
- <title>Replace GdkPixmap by cairo surfaces</title>
- <para>
- The #GdkPixmap object and related functions have been removed.
- In the cairo-centric world of GTK+ 3, cairo surfaces take over
- the role of pixmaps.
- </para>
- <example>
- <title>Creating custom cursors</title>
- <para>
- One place where pixmaps were commonly used is to create custom
- cursors:
- <informalexample><programlisting>
-GdkCursor *cursor;
-GdkPixmap *pixmap;
-cairo_t *cr;
-GdkColor fg = { 0, 0, 0, 0 };
-
-pixmap = gdk_pixmap_new (NULL, 1, 1, 1);
-
-cr = gdk_cairo_create (pixmap);
-cairo_rectangle (cr, 0, 0, 1, 1);
-cairo_fill (cr);
-cairo_destroy (cr);
-
-cursor = gdk_cursor_new_from_pixmap (pixmap, pixmap, &fg, &fg, 0, 0);
-
-g_object_unref (pixmap);
- </programlisting></informalexample>
- The same can be achieved without pixmaps, by drawing onto
- an image surface:
- <informalexample><programlisting>
-GdkCursor *cursor;
-cairo_surface_t *s;
-cairo_t *cr;
-GdkPixbuf *pixbuf;
-
-s = cairo_image_surface_create (CAIRO_FORMAT_A1, 3, 3);
-cr = cairo_create (s);
-cairo_arc (cr, 1.5, 1.5, 1.5, 0, 2 * M_PI);
-cairo_fill (cr);
-cairo_destroy (cr);
-
-pixbuf = gdk_pixbuf_get_from_surface (s,
- 0, 0,
- 3, 3);
-
-cairo_surface_destroy (s);
-
-cursor = gdk_cursor_new_from_pixbuf (display, pixbuf, 0, 0);
-
-g_object_unref (pixbuf);
- </programlisting></informalexample>
- </para>
- </example>
- </section>
-
- <section>
- <title>Replace GdkColormap by GdkVisual</title>
- <para>
- For drawing with cairo, it is not necessary to allocate colors, and
- a #GdkVisual provides enough information for cairo to handle colors
- in 'native' surfaces. Therefore, #GdkColormap and related functions
- have been removed in GTK+ 3, and visuals are used instead. The
- colormap-handling functions of #GtkWidget (gtk_widget_set_colormap(),
- etc) have been removed and gtk_widget_set_visual() has been added.
- </para>
- <example><title>Setting up a translucent window</title>
- <para>You might have a screen-changed handler like the following
- to set up a translucent window with an alpha-channel:
- </para>
- <informalexample><programlisting>
-static void
-on_alpha_screen_changed (GtkWidget *widget,
- GdkScreen *old_screen,
- GtkWidget *label)
-{
- GdkScreen *screen = gtk_widget_get_screen (widget);
- GdkColormap *colormap = gdk_screen_get_rgba_colormap (screen);
-
- if (colormap == NULL)
- colormap = gdk_screen_get_default_colormap (screen);
-
- gtk_widget_set_colormap (widget, colormap);
-}
- </programlisting></informalexample>
- <para>
- With visuals instead of colormaps, this will look as follows:
- </para>
- <informalexample><programlisting>
-static void
-on_alpha_screen_changed (GtkWindow *window,
- GdkScreen *old_screen,
- GtkWidget *label)
-{
- GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (window));
- GdkVisual *visual = gdk_screen_get_rgba_visual (screen);
-
- if (visual == NULL)
- visual = gdk_screen_get_system_visual (screen);
-
- gtk_widget_set_visual (window, visual);
-}
- </programlisting></informalexample>
- </example>
- </section>
-
- <section>
- <title>GdkDrawable is gone</title>
-
- <para>
- #GdkDrawable has been removed in GTK+ 3, together with #GdkPixmap
- and #GdkImage. The only remaining drawable class is #GdkWindow.
- For dealing with image data, you should use a #cairo_surface_t or
- a #GdkPixbuf.
- </para>
-
- <para>
- GdkDrawable functions that are useful with windows have been replaced
- by corresponding GdkWindow functions:
- <table>
- <title>GdkDrawable to GdkWindow</title>
- <tgroup cols="2">
- <thead>
- <row><entry>GDK 2.x</entry><entry>GDK 3</entry></row>
- </thead>
- <tbody>
- <row><entry>gdk_drawable_get_visual()</entry><entry>gdk_window_get_visual()</entry></row>
- <row><entry>gdk_drawable_get_size()</entry><entry>gdk_window_get_width()
- gdk_window_get_height()</entry></row>
- <row><entry>gdk_pixbuf_get_from_drawable()</entry><entry>gdk_pixbuf_get_from_window()</entry></row>
- <row><entry>gdk_drawable_get_clip_region()</entry><entry>gdk_window_get_clip_region()</entry></row>
- <row><entry>gdk_drawable_get_visible_region()</entry><entry>gdk_window_get_visible_region()</entry></row>
- </tbody>
- </tgroup>
- </table>
- </para>
- </section>
-
- <section>
- <title>Event filtering</title>
-
- <para>
- If your application uses the low-level event filtering facilities in GDK,
- there are some changes you need to be aware of.
- </para>
-
- <para>
- The special-purpose GdkEventClient events and the gdk_add_client_message_filter() and gdk_display_add_client_message_filter() functions have been
- removed. Receiving X11 ClientMessage events is still possible, using
- the general gdk_window_add_filter() API. A client message filter like
-<informalexample><programlisting>
-static GdkFilterReturn
-message_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
-{
- XClientMessageEvent *evt = (XClientMessageEvent *)xevent;
-
- /* do something with evt ... */
-}
-
- ...
-
-message_type = gdk_atom_intern ("MANAGER", FALSE);
-gdk_display_add_client_message_filter (display, message_type, message_filter, NULL);
-</programlisting></informalexample>
- then looks like this:
- <informalexample><programlisting>
-static GdkFilterReturn
-event_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
-{
- XClientMessageEvent *evt;
- GdkAtom message_type;
-
- if (((XEvent *)xevent)->type != ClientMessage)
- return GDK_FILTER_CONTINUE;
-
- evt = (XClientMessageEvent *)xevent;
- message_type = XInternAtom (evt->display, "MANAGER", FALSE);
-
- if (evt->message_type != message_type)
- return GDK_FILTER_CONTINUE;
-
- /* do something with evt ... */
-}
-
- ...
-
-gdk_window_add_filter (NULL, message_filter, NULL);
-</programlisting></informalexample>
- One advantage of using an event filter is that you can actually
- remove the filter when you don't need it anymore, using
- gdk_window_remove_filter().
- </para>
-
- <para>
- The other difference to be aware of when working with event filters
- in GTK+ 3 is that GDK now uses XI2 by default when available. That
- means that your application does not receive core X11 key or button
- events. Instead, all input events are delivered as XIDeviceEvents.
- As a short-term workaround for this, you can force your application
- to not use XI2, with gdk_disable_multidevice(). In the long term,
- you probably want to rewrite your event filter to deal with
- XIDeviceEvents.
- </para>
- </section>
-
- <section>
- <title>Backend-specific code</title>
- <para>
- In GTK+ 2.x, GDK could only be compiled for one backend at a time,
- and the %GDK_WINDOWING_X11 or %GDK_WINDOWING_WIN32 macros could
- be used to find out which one you are dealing with:
- <informalexample><programlisting>
-#ifdef GDK_WINDOWING_X11
- if (timestamp != GDK_CURRENT_TIME)
- gdk_x11_window_set_user_time (gdk_window, timestamp);
-#endif
-#ifdef GDK_WINDOWING_WIN32
- /* ... win32 specific code ... */
-#endif
- </programlisting></informalexample>
- In GTK+ 3, GDK can be built with multiple backends, and currently
- used backend has to be determined at runtime, typically using
- type-check macros on a #GdkDisplay or #GdkWindow. You still need
- to use the GDK_WINDOWING macros to only compile code referring
- to supported backends:
- <informalexample><programlisting>
-#ifdef GDK_WINDOWING_X11
- if (GDK_IS_X11_DISPLAY (display))
- {
- if (timestamp != GDK_CURRENT_TIME)
- gdk_x11_window_set_user_time (gdk_window, timestamp);
- }
- else
-#endif
-#ifdef GDK_WINDOWING_WIN32
- if (GDK_IS_WIN32_DISPLAY (display))
- {
- /* ... win32 specific code ... */
- }
- else
-#endif
- {
- g_warning ("Unsupported GDK backend");
- }
- </programlisting></informalexample>
- </para>
- <para>
- If you used the pkg-config variable <varname>target</varname> to
- conditionally build part of your project depending on the GDK backend,
- for instance like this:
- <informalexample><programlisting>
-AM_CONDITIONAL(BUILD_X11, test `$PKG_CONFIG --variable=target gtk+-2.0` = "x11")
- </programlisting></informalexample>
- then you should now use the M4 macro provided by GTK+ itself:
- <informalexample><programlisting>
-GTK_CHECK_BACKEND([x11], [3.0.2], [have_x11=yes], [have_x11=no])
-AM_CONDITIONAL(BUILD_x11, [test "x$have_x11" = "xyes"])
- </programlisting></informalexample>
- </para>
- </section>
-
- <section>
- <title>GtkPlug and GtkSocket</title>
-
- <para>
- The #GtkPlug and #GtkSocket widgets are now X11-specific, and you
- have to include the <filename><gtk/gtkx.h></filename> header
- to use them. The previous section about proper handling of
- backend-specific code applies, if you care about other backends.
- </para>
- </section>
-
- <section>
- <title>The GtkWidget::draw signal</title>
- <para>
- The GtkWidget #GtkWidget::expose-event signal has been replaced by
- a new #GtkWidget::draw signal, which takes a #cairo_t instead of
- an expose event. The cairo context is being set up so that the origin
- at (0, 0) coincides with the upper left corner of the widget, and
- is properly clipped.
- </para>
- <note><para>In other words, the cairo context of the draw signal is set
- up in 'widget coordinates', which is different from traditional expose
- event handlers, which always assume 'window coordinates'.
- </para></note>
- <para>
- The widget is expected to draw itself with its allocated size, which
- is available via the new gtk_widget_get_allocated_width() and
- gtk_widget_get_allocated_height() functions. It is not necessary to
- check for gtk_widget_is_drawable(), since GTK+ already does this check
- before emitting the #GtkWidget::draw signal.
- </para>
- <para>
- There are some special considerations for widgets with multiple windows.
- Expose events are window-specific, and widgets with multiple windows
- could expect to get an expose event for each window that needs to be
- redrawn. Therefore, multi-window expose event handlers typically look
- like this:
- <informalexample><programlisting>
- if (event->window == widget->window1)
- {
- /* ... draw window1 ... */
- }
- else if (event->window == widget->window2)
- {
- /* ... draw window2 ... */
- }
- ...
- </programlisting></informalexample>
- In contrast, the #GtkWidget::draw signal handler may have to draw multiple
- windows in one call. GTK+ has a convenience function
- gtk_cairo_should_draw_window() that can be used to find out if
- a window needs to be drawn. With that, the example above would look
- like this (note that the 'else' is gone):
- <informalexample><programlisting>
- if (gtk_cairo_should_draw_window (cr, widget->window1)
- {
- /* ... draw window1 ... */
- }
- if (gtk_cairo_should_draw_window (cr, widget->window2)
- {
- /* ... draw window2 ... */
- }
- ...
- </programlisting></informalexample>
- Another convenience function that can help when implementing
- ::draw for multi-window widgets is gtk_cairo_transform_to_window(),
- which transforms a cairo context from widget-relative coordinates
- to window-relative coordinates. You may want to use cairo_save() and
- cairo_restore() when modifying the cairo context in your draw function.
- </para>
- <para>
- All GtkStyle drawing functions (gtk_paint_box(), etc) have been changed
- to take a #cairo_t instead of a window and a clip area. ::draw
- implementations will usually just use the cairo context that has been
- passed in for this.
- </para>
- <example><title>A simple ::draw function</title>
- <programlisting>
-gboolean
-gtk_arrow_draw (GtkWidget *widget,
- cairo_t *cr)
-{
- GtkStyleContext *context;
- gint x, y;
- gint width, height;
- gint extent;
-
- context = gtk_widget_get_style_context (widget);
-
- width = gtk_widget_get_allocated_width (widget);
- height = gtk_widget_get_allocated_height (widget);
-
- extent = MIN (width - 2 * PAD, height - 2 * PAD);
- x = PAD;
- y = PAD;
-
- gtk_render_arrow (context, rc, G_PI / 2, x, y, extent);
-}
- </programlisting>
- </example>
- </section>
-
- <section>
- <title>GtkProgressBar orientation</title>
-
- <para>
- In GTK+ 2.x, #GtkProgressBar and #GtkCellRendererProgress were using the
- GtkProgressBarOrientation enumeration to specify their orientation and
- direction. In GTK+ 3, both the widget and the cell renderer implement
- #GtkOrientable, and have an additional 'inverted' property to determine
- their direction. Therefore, a call to gtk_progress_bar_set_orientation()
- needs to be replaced by a pair of calls to
- gtk_orientable_set_orientation() and gtk_progress_bar_set_inverted().
- The following values correspond:
- <table>
- <tgroup cols="3">
- <colspec colname="1"/>
- <colspec colname="2"/>
- <colspec colname="3"/>
- <thead>
- <row><entry>GTK+ 2.x</entry><entry namest="2" nameend="3">GTK+ 3</entry></row>
- <row><entry>GtkProgressBarOrientation</entry><entry>GtkOrientation</entry><entry>inverted</entry></row>
- </thead>
- <tbody>
- <row><entry>GTK_PROGRESS_LEFT_TO_RIGHT</entry><entry>GTK_ORIENTATION_HORIZONTAL</entry><entry>FALSE</entry></row>
- <row><entry>GTK_PROGRESS_RIGHT_TO_LEFT</entry><entry>GTK_ORIENTATION_HORIZONTAL</entry><entry>TRUE</entry></row>
- <row><entry>GTK_PROGRESS_TOP_TO_BOTTOM</entry><entry>GTK_ORIENTATION_VERTICAL</entry><entry>FALSE</entry></row>
- <row><entry>GTK_PROGRESS_BOTTOM_TO_TOP</entry><entry>GTK_ORIENTATION_VERTICAL</entry><entry>TRUE</entry></row>
- </tbody>
- </tgroup>
- </table>
- </para>
- </section>
-
- <section>
- <title>Check your expand and fill flags</title>
-
- <para>
- The behaviour of expanding widgets has changed slightly in GTK+ 3,
- compared to GTK+ 2.x. It is now 'inherited', i.e. a container that
- has an expanding child is considered expanding itself. This is often
- the desired behaviour. In places where you don't want this to happen,
- setting the container explicity as not expanding will stop the
- expand flag of the child from being inherited. See
- gtk_widget_set_hexpand() and gtk_widget_set_vexpand().
- </para>
- <para>
- If you experience sizing problems with widgets in ported code,
- carefully check the #GtkBox expand and #GtkBox fill child properties of your
- boxes.
- </para>
- </section>
-
- <section>
- <title>Scrolling changes</title>
-
- <para>
- The default values for the #GtkScrolledWindow:hscrollbar-policy and
- #GtkScrolledWindow:vscrollbar-policy properties have been changed from
- 'never' to 'automatic'. If your application was relying on the default
- value, you will have to set it explicitly.
- </para>
-
- <para>
- The ::set-scroll-adjustments signal on GtkWidget has been replaced
- by the #GtkScrollable interface which must be implemented by a widget
- that wants to be placed in a #GtkScrolledWindow. Instead of emitting
- ::set-scroll-adjustments, the scrolled window simply sets the
- #GtkScrollable:hadjustment and #GtkScrollable:vadjustment properties.
- </para>
- </section>
-
- <section>
- <title>GtkObject is gone</title>
-
- <para>
- GtkObject has been removed in GTK+ 3. Its remaining functionality,
- the ::destroy signal, has been moved to GtkWidget. If you have non-widget
- classes that are directly derived from GtkObject, you have to make
- them derive from #GInitiallyUnowned (or, if you don't need the floating
- functionality, #GObject). If you have widgets that override the
- destroy class handler, you have to adjust your class_init function,
- since destroy is now a member of GtkWidgetClass:
- <informalexample><programlisting>
- GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
-
- object_class->destroy = my_destroy;
- </programlisting></informalexample>
- becomes
- <informalexample><programlisting>
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
-
- widget_class->destroy = my_destroy;
- </programlisting></informalexample>
- In the unlikely case that you have a non-widget class that is derived
- from GtkObject and makes use of the destroy functionality, you have
- to implement ::destroy yourself.
- </para>
-
- <para>
- If your program used functions like gtk_object_get or gtk_object_set,
- these can be replaced directly with g_object_get or g_object_set. In
- fact, most every gtk_object_* function can be replaced with the
- corresponding g_object_ function, even in GTK+ 2 code. The one exception
- to this rule is gtk_object_destroy, which can be replaced with
- gtk_widget_destroy, again in both GTK+ 2 and GTK+ 3.
- </para>
- </section>
-
- <section>
- <title>GtkEntryCompletion signal parameters</title>
-
- <para>
- The #GtkEntryCompletion::match-selected and
- #GtkEntryCompletion::cursor-on-match signals were erroneously
- given the internal filter model instead of the users model.
- This oversight has been fixed in GTK+ 3; if you have handlers
- for these signals, they will likely need slight adjustments.
- </para>
- </section>
-
- <section>
- <title>Resize grips</title>
-
- <para>
- The resize grip functionality has been moved from #GtkStatusbar
- to #GtkWindow. Any window can now have resize grips, regardless whether
- it has a statusbar or not. The functions
- gtk_statusbar_set_has_resize_grip() and gtk_statusbar_get_has_resize_grip()
- have disappeared, and instead there are now
- gtk_window_set_has_resize_grip() and gtk_window_get_has_resize_grip().
- </para>
- <para>
- In more recent versions of GTK+ 3, the resize grip functionality has
- been removed entirely, in favor of invisible resize borders around the
- window. When updating to newer versions of GTK+ 3, you should simply
- remove all code dealing with resize grips.
- </para>
- </section>
-
- <section>
- <title>Prevent mixed linkage</title>
- <para>
- Linking against GTK+ 2.x and GTK+ 3 in the same process is problematic
- and can lead to hard-to-diagnose crashes. The gtk_init() function in
- both GTK+ 2.22 and in GTK+ 3 tries to detect this situation and abort
- with a diagnostic message, but this check is not 100% reliable (e.g. if
- the problematic linking happens only in loadable modules).
- </para>
- <para>
- Direct linking of your application against both versions of GTK+ is
- easy to avoid; the problem gets harder when your application is using
- libraries that are themselves linked against some version of GTK+.
- In that case, you have to verify that you are using a version of the
- library that is linked against GTK+ 3.
- </para>
- <para>
- If you are using packages provided by a distributor, it is likely that
- parallel installable versions of the library exist for GTK+ 2.x and
- GTK+ 3, e.g for vte, check for vte3; for webkitgtk look for webkitgtk3,
- and so on.
- </para>
- </section>
-
- <section>
- <title>Install GTK+ modules in the right place</title>
- <para>
- Some software packages install loadable GTK+ modules such as theme engines,
- gdk-pixbuf loaders or input methods. Since GTK+ 3 is parallel-installable
- with GTK+ 2.x, the two GTK+ versions have separate locations for their
- loadable modules. The location for GTK+ 2.x is
- <filename><replaceable>libdir</replaceable>/gtk-2.0</filename>
- (and its subdirectories), for GTK+ 3 the location is
- <filename><replaceable>libdir</replaceable>/gtk-3.0</filename>
- (and its subdirectories).
- </para>
- <para>
- For some kinds of modules, namely input methods and pixbuf loaders,
- GTK+ keeps a cache file with extra information about the modules.
- For GTK+ 2.x, these cache files are located in
- <filename><replaceable>sysconfdir</replaceable>/gtk-2.0</filename>.
- For GTK+ 3, they have been moved to
- <filename><replaceable>libdir</replaceable>/gtk-3.0/3.0.0/</filename>.
- The commands that create these cache files have been renamed with a -3
- suffix to make them parallel-installable.
- </para>
- <para>
- Note that GTK+ modules often link against libgtk, libgdk-pixbuf, etc.
- If that is the case for your module, you have to be careful to link the
- GTK+ 2.x version of your module against the 2.x version of the libraries,
- and the GTK+ 3 version against hte 3.x versions. Loading a module linked
- against libgtk 2.x into an application using GTK+ 3 will lead to
- unhappiness and must be avoided.
- </para>
- </section>
-
- </section>
-
-</chapter>
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
+]>
+<chapter id="gtk-migrating-2-to-4">
+ <title>Migrating from GTK+ 2.x to GTK+ 4</title>
+
+ <para>
+ If your application is still using GTK+ 2, you should first convert it to
+ GTK+ 3, by following the <ulink url="https://developer.gnome.org/gtk3/stable/gtk-migrating-2-to-3.html">migration guide</ulink> in the GTK+ 3
+ documentation.
+ </para>
+
+</chapter>
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
+]>
+<chapter id="gtk-migrating-3-to-4">
+ <title>Migrating from GTK+ 3.x to GTK+ 4</title>
+
+ <para>
+ Information about porting from GTK+ 3 to GTK+ 4 will appear here.
+ </para>
+
+</chapter>
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
-]>
-<chapter id="gtk-migrating-3-x-to-y">
- <title>Migrating from one GTK+ 3 release to another</title>
-
- <para>
- GTK+ 3 has seen considerable development over multiple stable releases.
- While we try to maintain compatibility as far as possible, some minor
- adjustments may be necessary when moving an application from one release
- of GTK+ 3 to the next.
- </para>
-
- <para>
- The following sections list noteworthy changes in GTK+ 3.x release that
- may or may not require applications to be updated.
- </para>
-
- <section>
- <title>Changes in GTK+ 3.2</title>
-
- <para>
- The accessible implementations for GTK+ widgets have been integrated
- into libgtk itself, and the gail module does not exist anymore. This
- change should not affect applications very much.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.4</title>
-
- <para>
- Scroll events have been separated from button events, and smooth
- scrolling has been added with a separate event mask. Widgets now
- need to have either GDK_SCROLL_MASK or GDK_SMOOTH_SCROLL_MASK in
- their event mask to receive scroll events. In addition, the
- GdkScrollDirection enumeration has gained a new member,
- GDK_SCROLL_SMOOTH, so switch statements will have to be amended
- to cover this case.
- </para>
-
- <para>
- GTK+ now uses <Primary> instead of <Control> in keyboard
- accelerators, for improved cross-platform handling. This should not
- affect applications, unless they parse or create these accelerator
- manually.
- </para>
-
- <para>
- The tacit assumption that the Alt key corresponds to the MOD1
- modifier under X11 is now a hard requirement.
- </para>
-
- <para>
- The beagle search backend for the file chooser has been dropped.
- Tracker is the only supported search backend on Linux now.
- </para>
-
- <para>
- GtkNotebook has been changed to destroy its action widgets when
- it gets destroyed itself. If your application is using action
- widgets in notebooks, you may have to adjust your code to take
- this into account.
- </para>
-
- <para>
- GtkApplication no longer uses the gtk_ mainloop wrappers, so
- it is no longer possible to use gtk_main_quit() to stop it.
- </para>
-
- <para>
- The -uninstalled variants of the pkg-config files have been dropped.
- </para>
-
- <para>
- Excessive dependencies have been culled from Requires: lines
- in .pc files. Dependent modules may have to declare dependencies
- that there were getting 'for free' in the past.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.6</title>
-
- <para>
- The accessibility bridge code that exports accessible objects
- on the bus is now used by default; atk-bridge has been converted
- into a library that GTK+ links against. To void the linking,
- pass --without-atk-bridge when configuring GTK+.
- </para>
-
- <para>
- GDK threading support has been deprecated. It is recommended to
- use g_idle_add(), g_main_context_invoke() and similar funtions
- to make all GTK+ calls from the main thread.
- </para>
-
- <para>
- GTK+ now follows the XDG Base Directory specification for
- user configuration and data files. In detail,
- <itemizedlist>
- <listitem>$XDG_CONFIG_HOME/gtk-3.0/custom-papers is the new location
- for $HOME/.gtk-custom-papers</listitem>
- <listitem>$XDG_CONFIG_HOME/gtk-3.0/bookmarks is the new location
- for $HOME/.gtk-bookmarks</listitem>
- <listitem>$XDG_DATA_HOME/themes is preferred over $HOME/.themes</listitem>
- <listitem>$XDG_DATA_HOME/icons is preferred over $HOME/.icons.</listitem>
- </itemizedlist>
- Existing files from the old location will still be read
- if the new location does not exist.
- </para>
-
- <para>
- $HOME/.gtk-3.0 is no longer in the default module load path.
- If you want to load modules from there, add it to the GTK_PATH
- environment variable.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.8</title>
-
- <para>
- GtkIconInfo has changed from being a boxed type to a GObject.
- This is technically an ABI change, but basically all existing code
- will keep working if its used as a boxed type, and it is not
- possible to instantiate GtkIconInfos outside GTK+, so this is
- not expected to be a big problem.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.10</title>
-
- <para>
- GDK has been changed to allow only a single screen per display.
- Only the X11 backend had multiple screens before, and multi-screen
- setups (not multi-monitor!) are very rare nowadays. If you really
- need multiple X screens, open them as separate displays.
- </para>
-
- <para>
- The behavior of GtkBox::expand has been changed to never propagate
- up. Previously, this was happening inconsistently. If you want the
- expand to propagate, use the GtkWidget h/v expand properties.
- If you experience sizing problems with widgets in ported code,
- carefully check the expand and fill flags of your boxes.
- </para>
-
- <para>
- GtkBin no longer provides default implementations for
- get_height_for_width, subclasses now have to provide their own
- implementation if they need height-for-width functionality.
- </para>
-
- <para>
- Widget state propagation has been changed. Historically, all of
- active, prelight, selected, insensitive, inconsistent and backdrop
- have been propagated to children. This has now been restricted
- to just the insensitive and backdrop states. This mostly affects
- theming.
- </para>
-
- <para>
- The way widget drawing happens has changed. Earlier versions handled
- one expose event per GdkWindow, each with a separate cairo_t. Now we
- only handle the expose event on the toplevel and reuse the same
- cairo_t (with the right translation and clipping) for the entire
- widget hierarchy, recursing down via the GtkWidget::draw signal.
- Having all rendering in the same call tree allows effects like
- opacity and offscreen rendering of entire widget sub-hierarchies.
- Generally this should not require any changes in widgets, but
- code looking at e.g. the current expose event may see different
- behavior than before.
- </para>
-
- <para>
- The Gtk+ scrolling implementation has changed. gdk_window_scroll()
- and gdk_window_move_region() no longer copy the region on the
- window, but rather invalidate the entire scrolled region. This is
- slightly slower, but allowed us to implement a offscreen surface
- scrolling method which better fits modern hardware. Most scrolling
- widgets in Gtk+ have been converted to use this model for scrolling,
- but external widgets implementing scrolling using GdkWindow may see
- some slowdown.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.12</title>
-
- <para>
- GtkWidget had a hack where if opacity is 0.999 we set up an opacity
- group when rendering the widget. This is no longer needed in 3.10,
- and GtkStack doesn't use it anymore. It has been removed in 3.12.
- GdStack is using it, so applications should be ported from GdStack
- to GtkStack in 3.12.
- </para>
-
- <para>
- GtkHeaderBar in 3.10 was not ordering its pack-end children in
- the right way. This has been fixed in 3.12. Applications which
- pack multiple widgets at the end of a headerbar will have to
- be updated.
- </para>
-
- <para>
- gtk_text_view_add_child_in_window has changed behaviour a bit.
- It now always positions the child in buffer coordinates, where
- it used to inconsistently scroll with the buffer but then go
- reposition to a window-relative position on redraw.
- </para>
-
- <para>
- A number of container widgets have been made more compliant with
- the uniform CSS rendering model by making them render backgrounds
- and borders. This may require some adjustments in applications that
- were making assumptions about containers never rendering backgrounds.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.14</title>
-
- <para>
- A new state, GTK_STATE_FLAG_CHECKED, has been added for checked states
- of radio and check buttons and menuitems. Applications that are using
- GTK+ styles without widgets will need adjustments.
- </para>
-
- <para>
- Adwaita is now the default theme on all platforms.
- </para>
-
- <para>
- The icon theme code has become a little pickier about sizes and is not
- automatically scaling icons beyond the limits defined in the icon theme
- unless explicitly asked to do so with GTK_ICON_LOOKUP_FORCE_SIZE.
- </para>
-
- <para>
- GTK+ now includes an interactive debugger which can be activated with
- the keyboard shortcuts Ctrl-Shift-d or Ctrl-Shift-i. If these shortcuts
- interfere with application keybindings, they can be disabled with the
- setting org.gtk.Settings.Debug.enable-inspector-keybinding.
- </para>
-
- <para>
- Most widgets have been ported to use the new gesture framework internally
- for event handling. Traditional event handlers in derived widgets are still
- being called.
- </para>
-
- <para>
- Using GTK+ under X11 without the X Render extension has been observed
- to be problematic. This combination is using code paths in cairo and
- graphics drivers which are rarely tested and likely buggy.
- </para>
-
- <para>
- GtkTextView is now using a pixel-cache internally, and is drawing
- a background underneath the text. This can cause problems for applications
- which assumed that they could draw things below and above the text
- by chaining up in the ::draw implementation of their GtkTextView subclass.
- As a short-term workaround, you can make the application apply a
- custom theme to the text view with a transparent background. For
- a proper fix, use the new ::draw_layer vfunc.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.16</title>
-
- <para>
- GTK+ now includes an OpenGL rendering widget. To support GL on various
- platforms, GTK+ uses libepoxy.
- </para>
-
- <para>
- GTK+ no longer uses gtk-update-icon-cache during its build. The
- --enable-gtk2-dependency configure option has been removed.
- </para>
-
- <para>
- The introspection annotations for the x and y parameters of
- GtkMenuPositionFunc have been corrected from 'out' to 'inout'.
- If you are using such a function from language-bindings, this
- may require adjustments.
- </para>
-
- <para>
- The lookup order for actions that are activated via keyboard
- accelerators has been changed to start at the currently focused
- widget. If your application is making use fo nested action groups
- via gtk_widget_insert_action_group, you may want to check that
- this change does not upset your accelerators.
- </para>
-
- <para>
- The GtkScrollable interface has gained a new vfunc, get_border,
- that is used to position overshoot and undershoot indications that
- are drawn over the content by GtkScrolledWindow. Unless your scrollable
- has non-scrolling parts similar to treeview headers, there is no need
- to implement this vfunc.
- </para>
-
- <para>
- The GtkSearchEntry widget has gained a number of new signals that
- are emitted when certain key sequences are seen. In particular, it
- now handles the Escape key and emits ::stop-search. Applications that
- expect to handle Escape themselves will need to be updated.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.18</title>
-
- <para>
- The GtkListBox model support that was introduced in 3.16 has been
- changed to no longer call gtk_widget_show_all on rows created by
- the create_widget_func. You need to manage the visibility of child
- widgets yourself in your create_widget_func.
- </para>
-
- <para>
- The alpha component of foreground colors that are applied to
- GtkCellRendererText is no longer ignored. If you don't want your
- text to be translucent, use opaque colors.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.20</title>
-
- <para>
- The way theming works in GTK+ has been reworked fundamentally, to
- implement many more CSS features and make themes more expressive.
- As a result, custom CSS that is shipped with applications and third-party
- themes will need adjustments. Widgets now use element names much more
- than style classes; type names are no longer used in style matching.
- Every widget now documents the element names it has and the style classes
- it uses. The GTK+ inspector can also help with finding this information.
- </para>
-
- <para>
- GTK+ now uses internal subobjects (also known as gadgets) for allocating
- and drawing widget parts. Applications that subclass GTK+ widgets may see
- warnings if they override the size_allocate vfunc and don't chain up.
- The proper way to subclass is to chain up in size_allocate. If you do not
- want to do that for some reason, you have to override the draw vfunc as
- well.
- </para>
-
- <para>
- Several fixes for window sizing and window placement with client-side
- decorations may affect applications that are saving and restoring window
- sizes. The recommended best practice for this which is known to work with
- client-side and server-side decorations and with older and newer versions
- of GTK+ is to use gtk_window_get_size() to save window sizes and
- gtk_window_set_default_size() to restore it.
- See https://wiki.gnome.org/HowDoI/SaveWindowState for a detailed example.
- </para>
-
- <para>
- Geometry handling in GtkWindow has been removed. If you are using the
- functions gtk_window_resize_to_geometry, gtk_window_set_default_geometry,
- gtk_window_parse_geometry or gtk_window_set_geometry_hints, you may need
- to make some changes to your code.
- </para>
-
- <para>
- GtkDrawingArea used to implicitly render the theme background before
- calling the ::draw handler. This is no longer the case. If you rely
- on having a theme-provided background, call gtk_render_background()
- from your ::draw handler.
- </para>
-
- <para>
- The GtkFileChooser interface prerequisite changed from GtkWidget
- to GObject, allowing non-widget implementations of this interface.
- This is a minor change in ABI, as applications are no longer guaranteed
- that a GtkFileChooser also supports all GtkWidget methods. However, all
- previously existing implementations still derive from GtkWidget, so no
- existing code should break.
- </para>
-
- <para>
- The way in which GtkLevelBar determines the offset to apply was a bit
- inconsistent in the past; this has been fixed. Applications that are using
- custom offsets should double-check that their levels look as expected.
- </para>
- </section>
-
- <section>
- <title>Changes in GTK+ 3.22</title>
-
- <para>
- The CSS parser has gotten a bit more selective in what it accepts as
- valid values for the font: shorthand. Following the CSS specification,
- at least a size and a family name are required now. If you want to
- change an individual facet of the font, like the weight, use the
- individual CSS properties: font-weight, font-size, font-family, etc.
- </para>
-
- <para>
- The CSS parser now warns about some more constructs that are not according
- to the CSS spec, such as gradients with a single color stop. Instead,
- you can just use image(<color>).
- </para>
-
- <para>
- The #GtkSizeGroup:ignore-hidden property has not been working properly
- for a long time, and we've not documented it as broken and deprecated.
- The recommended alternative for reserving space of widgets that are not
- currently shown in the UI is to use a #GtkStack (with some 'filler'
- widget, e.g. an empty #GtkBox, in another page).
- </para>
-
- <para>
- GtkHeaderBar now respects the hexpand property for its custom title
- widget and its packed children. This change may inadvertently cause the
- layout of those children to change, if they unintentionally had hexpand
- set before.
- </para>
-
- <para>
- The behavior of the expand flag in #GtkTables #GtkAttachOptions has been
- changed to (again) match the behavior in #GtkBox and in GTK+ 2.x. These
- options don't cause the table itself to expand.
- </para>
-
- <para>
- The way GtkPopover behaved during a call to gtk_widget_hide() violated
- some of the internal assumptions GTK+ makes about widget visibility.
- gtk_popover_popup() and gtk_popover_popdown() have been introduced to
- show or hide the popover with a transition, while gtk_widget_show()
- and gtk_widget_hide() on a GtkPopover now work the same way they do
- on any other widget and immediately hide (or show) the popover.
- </para>
- </section>
-</chapter>
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-]>
-<chapter id="gtk-migrating-GtkGrid">
-
- <title>Migrating from other containers to GtkGrid</title>
-
- <para>
- #GtkGrid is an attempt to write a comprehensive, legacy-free,
- box-layout container that is flexible enough to replace #GtkBox,
- #GtkTable and the like.
- </para>
-
- <para>
- The layout model of GtkGrid is to arrange its children in rows and
- columns. This is done by assigning positions on a two-dimentions
- grid that stretches arbitrarily far in all directions.
- Children can span multiple rows or columns, too.
- </para>
-
- <section>
-
- <title>GtkBox versus GtkGrid: packing</title>
-
- <para>
- GtkBox works by arranging child widgets in a single line, either
- horizontally or vertically. It allows packing children from the
- beginning or end, using gtk_box_pack_start() and gtk_box_pack_end().
- </para>
-
- <inlinegraphic fileref="box-packing.png" format="PNG"></inlinegraphic>
-
- <example>
- <title>A simple box</title>
- <programlisting>
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-
- gtk_box_pack_start (GTK_BOX (box), gtk_label_new ("One"), FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (box), gtk_label_new ("Two"), FALSE, FALSE, 0);
- </programlisting>
- <para>This can be done with #GtkGrid as follows:</para>
- <programlisting>
- grid = gtk_grid_new ();
-
- child1 = gtk_label_new ("One");
- gtk_grid_attach (GTK_GRID (grid), child1, 0, 0, 1, 1);
- child2 = gtk_label_new ("Two");
- gtk_grid_attach_next_to (GTK_GRID (grid), child2, child1, GTK_POS_RIGHT, 1, 1);
- </programlisting>
- <para>
- And similarly for gtk_box_pack_end(). In that case, you
- would use #GTK_POS_LEFT to place the grid children from
- left to right.
- </para>
- <para>
- If you only need to pack children from the start, using
- gtk_container_add() is an even simpler alternative. GtkGrid
- places children added with gtk_container_add() in a single
- row or column according to its #GtkOrientable:orientation.
- </para>
- </example>
-
- <para>
- One difference to keep in mind is that the gtk_box_pack_start/pack_end
- functions allow you to place an arbitrary number of children from
- either end without ever 'colliding in the middle'. With GtkGrid, you
- have to leave enough space between the two ends, if you want to combine
- packing from both ends towards the middle. In practice, this should be
- easy to avoid; and GtkGrid simply ignores entirely empty rows or
- columns for layout and spacing.
- </para>
- <para>
- On the other hand, GtkGrid is more flexible in that its grid extends
- indefinitively in both directions — there is no problem with
- using negative numbers for the grid positions. So, if you discover
- that you need to place a widget before your existing arrangement,
- you always can.
- </para>
- </section>
-
- <section>
- <title>GtkBox versus GtkGrid: sizing</title>
-
- <para>
- When adding a child to a GtkBox, there are two hard-to-remember
- parameters (child properties, more exactly) named expand and fill
- that determine how the child size behaves in the main direction
- of the box. If expand is set, the box allows the position occupied
- by the child to grow when extra space is available. If fill is
- also set, the extra space is allocated to the child widget itself.
- Otherwise it is left 'free'.
- There is no control about the 'minor' direction; children
- are always given the full size in the minor direction.
- </para>
-
- <inlinegraphic fileref="box-expand.png" format="PNG"></inlinegraphic>
-
- <para>
- GtkGrid does not have any custom child properties for controlling
- size allocation to children. Instead, it fully supports the newly
- introduced #GtkWidget:hexpand, #GtkWidget:vexpand, #GtkWidget:halign
- and #GtkWidget:valign properties.
- </para>
- <para>
- The #GtkWidget:hexpand and #GtkWidget:vexpand properties operate
- in a similar way to the expand child properties of #GtkBox. As soon
- as a column contains a hexpanding child, GtkGrid allows the column
- to grow when extra space is available (similar for rows and vexpand).
- In contrast to GtkBox, all the extra space is always allocated
- to the child widget, there are no 'free' areas.
- </para>
- <para>
- To replace the functionality of the fill child properties, you can
- set the #GtkWidget:halign and #GtkWidget:valign properties. An
- align value of #GTK_ALIGN_FILL has the same effect as setting fill
- to %TRUE, a value of #GTK_ALIGN_CENTER has the same effect as setting
- fill to %FALSE. The image below shows the effect of various combinations
- of halign and valign.
- </para>
-
- <inlinegraphic fileref="widget-hvalign.png" format="PNG"></inlinegraphic>
-
- <example>
- <title>Expansion and alignment</title>
- <programlisting>
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-
- gtk_box_pack_start (GTK_BOX (box), gtk_label_new ("One"), TRUE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (box), gtk_label_new ("Two"), TRUE, TRUE, 0);
- </programlisting>
- <para>This can be done with #GtkGrid as follows:</para>
- <programlisting>
- grid = gtk_grid_new ();
-
- child1 = gtk_label_new ("One");
- gtk_widget_set_hexpand (child1, TRUE);
- gtk_widget_set_halign (child1, GTK_ALIGN_CENTER);
- gtk_grid_attach (GTK_GRID (grid), child1, 0, 0, 1, 1);
- child2 = gtk_label_new ("Two");
- gtk_widget_set_hexpand (child2, TRUE);
- gtk_widget_set_halign (child1, GTK_ALIGN_FILL);
- gtk_grid_attach_next_to (GTK_GRID (grid), child2, child1, GTK_POS_RIGHT, 1, 1);
- </programlisting>
- </example>
- <para>
- One difference between the new GtkWidget expand properties and
- the GtkBox child property of the same name is that widget expandability
- is 'inherited' from children. What this means is that a container
- will become itself expanding as soon as it has
- an expanding child. This is typically what you want, it lets
- you e.g. mark the content pane of your application window as
- expanding, and all the intermediate containers between the
- content pane and the toplevel window will automatically do
- the right thing. This automatism can be overridden at any
- point by setting the expand flags on a container explicitly.
- </para>
- <para>
- Another difference between GtkBox and GtkGrid with respect to
- expandability is when there are no expanding children at all.
- In this case, GtkBox will forcibly expand all children whereas
- GtkGrid will not. In practice, the effect of this is typically
- that a grid will 'stick to the corner' when the toplevel
- containing it is grown, instead of spreading out its children
- over the entire area. The problem can be fixed by setting some
- or all of the children to expand.
- </para>
-
- <para>
- When you set the #GtkBox:homogeneous property on a GtkBox,
- it reserves the same space for all its children. GtkGrid does
- this in a very similar way, with #GtkGrid:row-homogeneous and
- #GtkGrid:column-homogeneous properties which control whether
- all rows have the same height and whether all columns have
- the same width.
- </para>
- </section>
-
- <section>
- <title>GtkBox versus GtkGrid: spacing</title>
-
- <para>
- With GtkBox, you have to specify the #GtkBox:spacing when
- you construct it. This property specifies the space that
- separates the children from each other. Additionally, you
- can specify extra space to put around each child individually,
- using the #GtkBox padding child property.
- </para>
-
- <para>
- GtkGrid is very similar when it comes to spacing between the
- children, except that it has two separate properties,
- #GtkGrid:row-spacing and #GtkGrid:column-spacing, for the
- space to leave between rows and columns. Note that row-spacing
- is the space <emphasis>between</emphasis> rows, not inside
- a row. So, if you doing a horizontal layout, you need to set
- #GtkGrid:column-spacing.
- </para>
- <para>
- GtkGrid doesn't have any custom child properties to specify
- per-child padding; instead you can use the #GtkWidget:margin
- property. You can also set different padding on each side with
- the #GtkWidget:margin-left, #GtkWidget:margin-right,
- #GtkWidget:margin-top and #GtkWidget:margin-bottom properties.
- </para>
-
- <example>
- <title>Spacing in boxes</title>
-
- <programlisting>
- box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
- gtk_box_pack_start (GTK_BOX (box), child, FALSE, FALSE, 12);
- </programlisting>
- <para>This can be done with #GtkGrid as follows:</para>
- <programlisting>
- grid = gtk_grid_new ();
- gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
- g_object_set (child, "margin", 12, NULL);
- gtk_grid_attach (GTK_GRID (box), child, 0, 0, 1, 1);
- </programlisting>
- </example>
- </section>
-
-<!--
- <section>
- <title>GtkTable versus GtkGrid</title>
- cover here: spanning, attachment points, grid size, attach options vs expand/align
-
- </section>
--->
-</chapter>
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-]>
-<chapter id="gtk-migrating-GtkStyleContext">
- <title>Theming changes</title>
-
- <para>
- In GTK+ 3.0, #GtkStyleContext was added to replace #GtkStyle and
- the theming infrastructure available in 2.x. GtkStyleContext is an
- object similar in spirit to GtkStyle, as it contains theming information,
- although in a more complete and tokenized fashion. There are two aspects
- to switching to GtkStyleContext: porting themes and theme engines, and
- porting applications, libraries and widgets.
- </para>
-
- <section id="gtk-migrating-GtkStyleContext-themes">
- <title>Migrating themes</title>
-
- <para>
- From GTK+ 3.0 on, theme engines must implement #GtkThemingEngine and be
- installed in <filename>$libdir/gtk+-3.0/$GTK_VERSION/theming-engines</filename>,
- and the files containing style information must be written in the CSS-like
- format that is understood by #GtkCssProvider. For a theme named
- "Clearlooks", the CSS file parsed by default is
- <filename>$datadir/themes/Clearlooks/gtk-3.0/gtk.css</filename>,
- with possible variants such as the dark theme being named
- <filename>gtk-dark.css</filename> in the same directory.
- </para>
-
- <para>
- If your theme RC file was providing values for #GtkSettings, you
- can install a <filename>settings.ini</filename> keyfile along with
- the <filename>gtk.css</filename> to provide theme-specific defaults
- for settings.
- </para>
-
- <para>
- Key themes have been converted to CSS syntax too. See the
- <link linkend="css-binding-set">GtkCssProvider</link> documentation
- information about the syntax. GTK+ looks for key themes in the file
- <filename>$datadir/themes/<replaceable>theme</replaceable>/gtk-3.0/gtk-keys.css</filename>, where <replaceable>theme</replaceable> is the current
- key theme name.
- </para>
- </section>
-
- <section id="gtk-migrating-theme-GtkStyleContext-engines">
- <title>Migrating theme engines</title>
-
- <para>
- Migrating a #GtkStyle based engine to a #GtkThemingEngine based one
- should be straightforward for most of the vfuncs. Besides a cleanup
- in the available paint methods and a simplification in the passed
- arguments (in favor of #GtkStyleContext containing all the information),
- the available render methods resemble those of #GtkStyle quite
- evidently. Notable differences include:
- </para>
-
- <orderedlist>
- <listitem>
- All variations of gtk_paint_box(), gtk_paint_flat_box(),
- gtk_paint_shadow(), gtk_paint_box_gap() and gtk_paint_shadow_gap()
- are replaced by gtk_render_background(), gtk_render_frame() and
- gtk_render_frame_gap(). The first function renders frameless
- backgrounds and the last two render frames in various forms.
- </listitem>
- <listitem>
- gtk_paint_resize_grip() has been subsumed by gtk_render_handle()
- with a #GTK_STYLE_CLASS_GRIP class set in the style context.
- </listitem>
- <listitem>
- gtk_paint_spinner() disappears in favor of gtk_render_activity()
- with a #GTK_STYLE_CLASS_SPINNER class set in the style context.
- </listitem>
- </orderedlist>
-
- <para>
- The list of available render methods is:
- </para>
-
- <simplelist>
- <member>
- gtk_render_background(): Renders a widget/area background.
- </member>
- <member>
- gtk_render_frame(): Renders a frame border around the given rectangle.
- Usually the detail of the border depends on the theme information,
- plus the current widget state.
- </member>
- <member>
- gtk_render_frame_gap(): Renders a frame border with a gap on one side.
- </member>
- <member>
- gtk_render_layout(): Renders a #PangoLayout.
- </member>
- <member>
- gtk_render_handle(): Renders all kind of handles and resize grips,
- depending on the style class.
- </member>
- <member>
- gtk_render_check(): Render checkboxes.
- </member>
- <member>
- gtk_render_option(): Render radiobuttons.
- </member>
- <member>
- gtk_render_arrow(): Renders an arrow pointing to a direction.
- </member>
- <member>
- gtk_render_expander(): Renders an expander indicator, such as in
- #GtkExpander.
- </member>
- <member>
- gtk_render_focus(): Renders the indication that a widget has the
- keyboard focus.
- </member>
- <member>
- gtk_render_line(): Renders a line from one coordinate to another.
- </member>
- <member>
- gtk_render_slider(): Renders a slider, such as in #GtkScale.
- </member>
- <member>
- gtk_render_extension(): Renders an extension that protrudes from
- a UI element, such as a notebook tab.
- </member>
- <member>
- gtk_render_activity(): Renders an area displaying activity, be it
- a progressbar or a spinner.
- </member>
- <member>
- gtk_render_icon_pixbuf(): Renders an icon into a #GdkPixbuf.
- </member>
- </simplelist>
-
- <para>
- One of the main differences to #GtkStyle<!-- -->-based engines is that the
- rendered widget is totally isolated from the theme engine, all style
- information is meant to be retrieved from the #GtkThemingEngine API,
- or from the #GtkWidgetPath obtained from gtk_theming_engine_get_path(),
- which fully represents the rendered widget's hierarchy from a styling
- point of view.
- </para>
-
- <para>
- The detail string available in #GtkStyle<!-- -->-based engines has been
- replaced by widget regions and style classes. Regions are a way for
- complex widgets to associate different styles with different areas,
- such as even and odd rows in a treeview. Style classes allow sharing
- of style information between widgets, regardless of their type.
- Regions and style classes can be used in style sheets to associate
- styles, and them engines can also access them. There are several
- predefined classes and regions such as %GTK_STYLE_CLASS_BUTTON or
- %GTK_STYLE_REGION_TAB in <filename>gtkstylecontext.h</filename>,
- although custom widgets may define their own, which themes may
- attempt to handle.
- </para>
-
- </section>
-
- <section id="gtk-migrating-GtkStyleContext-parser-extensions">
- <title>Extending the CSS parser</title>
-
- <para>
- In #GtkStyle<!-- -->-based engines, GtkRCStyle provided ways to extend the
- gtkrc parser with engine-specific extensions. This has been replaced
- by gtk_theming_engine_register_property(), which lets a theme engine
- register new properties with an arbitrary type. While there is built-in
- support for most basic types, it is possible to use a custom parser
- for the property.
- </para>
-
- <para>
- The installed properties depend on the #GtkThemingEngine:name property,
- so they should be added in the <literal>constructed()</literal> vfunc.
- For example, if an engine with the name "Clearlooks" installs a
- "focus-color" property with the type #GdkRGBA, the property
- <literal>-Clearlooks-focus-color</literal> will be registered and
- accepted in CSS like this:
- <informalexample><programlisting>
- GtkEntry {
- -Clearlooks-focus-color: rgba(255, 0, 0, 1.0);
- }
- </programlisting></informalexample>
- </para>
-
- <para>
- Widget style properties also follow a similar syntax, with the widget
- type name used as a prefix. For example, the #GtkWidget focus-line-width
- style property can be modified in CSS as
- <literal>-GtkWidget-focus-line-width</literal>.
- </para>
- </section>
-
- <section id="gtk-migrating-GtkStyleContext-css">
- <title>Using the CSS file format</title>
-
- <para>
- The syntax of RC and CSS files formats is obviously different.
- The CSS-like syntax will hopefully be much more familiar to many
- people, lowering the barrier for custom theming.
- </para>
- <para>
- Instead of going through the syntax differences one-by-one, we
- will present a more or less comprehensive example and discuss
- how it can be translated into CSS:
- </para>
-
- <example>
- <title>Sample RC code</title>
- <programlisting>
- style "default" {
- xthickness = 1
- ythickness = 1
-
- GtkButton::child-displacement-x = 1
- GtkButton::child-displacement-y = 1
- GtkCheckButton::indicator-size = 14
-
- bg[NORMAL] = @bg_color
- bg[PRELIGHT] = shade (1.02, @bg_color)
- bg[SELECTED] = @selected_bg_color
- bg[INSENSITIVE] = @bg_color
- bg[ACTIVE] = shade (0.9, @bg_color)
-
- fg[NORMAL] = @fg_color
- fg[PRELIGHT] = @fg_color
- fg[SELECTED] = @selected_fg_color
- fg[INSENSITIVE] = darker (@bg_color)
- fg[ACTIVE] = @fg_color
-
- text[NORMAL] = @text_color
- text[PRELIGHT] = @text_color
- text[SELECTED] = @selected_fg_color
- text[INSENSITIVE] = darker (@bg_color)
- text[ACTIVE] = @selected_fg_color
-
- base[NORMAL] = @base_color
- base[PRELIGHT] = shade (0.95, @bg_color)
- base[SELECTED] = @selected_bg_color
- base[INSENSITIVE] = @bg_color
- base[ACTIVE] = shade (0.9, @selected_bg_color)
-
- engine "clearlooks" {
- colorize_scrollbar = TRUE
- style = CLASSIC
- }
- }
-
- style "tooltips" {
- xthickness = 4
- ythickness = 4
-
- bg[NORMAL] = @tooltip_bg_color
- fg[NORMAL] = @tooltip_fg_color
- }
-
- style "button" {
- xthickness = 3
- ythickness = 3
-
- bg[NORMAL] = shade (1.04, @bg_color)
- bg[PRELIGHT] = shade (1.06, @bg_color)
- bg[ACTIVE] = shade (0.85, @bg_color)
- }
-
- style "entry" {
- xthickness = 3
- ythickness = 3
-
- bg[SELECTED] = mix (0.4, @selected_bg_color, @base_color)
- fg[SELECTED] = @text_color
-
- engine "clearlooks" {
- focus_color = shade (0.65, @selected_bg_color)
- }
- }
-
- style "other" {
- bg[NORMAL] = #fff;
- }
-
- class "GtkWidget" style "default"
- class "GtkEntry" style "entry"
- widget_class "*<GtkButton>" style "button"
- widget "gtk-tooltip*" style "tooltips"
- widget_class "window-name.*.GtkButton" style "other"
- </programlisting>
- </example>
-
- <para>
- would roughly translate to this CSS:
- </para>
-
- <example>
- <title>CSS translation</title>
- <programlisting>
- * {
- padding: 1;
- -GtkButton-child-displacement-x: 1;
- -GtkButton-child-displacement-y: 1;
- -GtkCheckButton-indicator-size: 14;
-
- background-color: @bg_color;
- color: @fg_color;
-
- -Clearlooks-colorize-scrollbar: true;
- -Clearlooks-style: classic;
- }
-
- *:hover {
- background-color: shade (@bg_color, 1.02);
- }
-
- *:selected {
- background-color: @selected_bg_color;
- color: @selected_fg_color;
- }
-
- *:insensitive {
- color: shade (@bg_color, 0.7);
- }
-
- *:active {
- background-color: shade (@bg_color, 0.9);
- }
-
- .tooltip {
- padding: 4;
-
- background-color: @tooltip_bg_color;
- color: @tooltip_fg_color;
- }
-
- .button {
- padding: 3;
- background-color: shade (@bg_color, 1.04);
- }
-
- .button:hover {
- background-color: shade (@bg_color, 1.06);
- }
-
- .button:active {
- background-color: shade (@bg_color, 0.85);
- }
-
- .entry {
- padding: 3;
-
- background-color: @base_color;
- color: @text_color;
- }
-
- .entry:selected {
- background-color: mix (@selected_bg_color, @base_color, 0.4);
- -Clearlooks-focus-color: shade (0.65, @selected_bg_color)
- }
-
- /* The latter selector is an specification of the first,
- since any widget may use the same classes or names */
- #window-name .button,
- GtkWindow#window-name GtkButton.button {
- background-color: #fff;
- }
- </programlisting>
- </example>
-
- <para>
- One notable difference is the reduction from fg/bg/text/base colors
- to only foreground/background, in exchange the widget is able to render
- its various elements with different CSS classes, which can be themed
- independently.
- </para>
-
- <para>
- In the same vein, the light, dark and mid color variants that
- were available in GtkStyle should be replaced by a combination of
- symbolic colors and custom CSS, where necessary. text_aa should
- really not be used anywhere, anyway, and the white and black colors
- that were available in GtkStyle can just be replaced by literal
- GdkRGBA structs.
- </para>
-
- <para>
- Access to colors has also changed a bit. With #GtkStyle, the common
- way to access colors is:
- <informalexample><programlisting>
- GdkColor *color1;
- GdkColor color2;
-
- color1 = &style->bg[GTK_STATE_PRELIGHT];
- gtk_style_lookup_color (style, "focus_color", &color2);
- </programlisting></informalexample>
- With #GtkStyleContext, you generally use #GdkRGBA instead of #GdkColor
- and the code looks like this:
- <informalexample><programlisting>
- GdkRGBA *color1;
- GdkRGBA color2;
-
- gtk_style_context_get (context, GTK_STATE_FLAG_PRELIGHT,
- "background-color", &color1,
- NULL);
- gtk_style_context_lookup_color (context, "focus_color", &color2);
-
- ...
-
- gdk_rgba_free (color1);
- </programlisting></informalexample>
- Note that the memory handling here is different: gtk_style_context_get()
- expects the address of a GdkRGBA* and returns a newly allocated struct,
- gtk_style_context_lookup_color() expects the address of an existing
- struct, and fills it.
- </para>
-
- <para>
- It is worth mentioning that the new file format does not support
- custom keybindings nor stock icon mappings as the RC format did.
- </para>
- </section>
-
- <section id="gtk-migrating-GtkStyleContext-checklist">
- <title>A checklist for widgets</title>
-
- <para>
- When porting your widgets to use #GtkStyleContext, this checklist
- might be useful.
- </para>
-
- <orderedlist>
- <listitem>
- Replace #GtkWidget::style-set handlers with
- #GtkWidget::style-updated handlers.
- </listitem>
-
- <listitem>
- <para>
- Try to identify the role of what you're rendering with any number
- of classes. This will replace the detail string. There is a predefined
- set of CSS classes which you can reuse where appropriate. Doing so
- will give you theming 'for free', whereas custom classes will require
- extra work in the theme. Note that complex widgets are likely to
- need different styles when rendering different parts, and style
- classes are one way to achieve this. This could result in code like
- the following (simplified) examples:
- </para>
-
- <example>
- <title>Setting a permanent CSS class</title>
- <programlisting>
- static void
- gtk_button_init (GtkButton *button)
- {
- GtkStyleContext *context;
-
- ...
-
- context = gtk_widget_get_style_context (GTK_WIDGET (button));
-
- /* Set the "button" class */
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
- }
- </programlisting>
- </example>
-
- <para>
- Or
- </para>
-
- <example>
- <title>Using dynamic CSS classes for different elements</title>
- <programlisting>
- static gboolean
- gtk_spin_button_draw (GtkSpinButton *spin,
- cairo_t *cr)
- {
- GtkStyleContext *context;
-
- ...
-
- context = gtk_widget_get_style_context (GTK_WIDGET (spin));
-
- gtk_style_context_save (context);
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY);
-
- /* Call to entry draw impl with "entry" class */
- parent_class->draw (spin, cr);
-
- gtk_style_context_restore (context);
- gtk_style_context_save (context);
-
- /* Render up/down buttons with the "button" class */
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
- draw_up_button (spin, cr);
- draw_down_button (spin, cr);
-
- gtk_style_context_restore (context);
-
- ...
- }
- </programlisting>
- </example>
-
- <para>
- Note that #GtkStyleContext only provides fg/bg colors, so text/base
- is done through distinctive theming of the different classes. For
- example, an entry would usually be black on white while a button
- would usually be black on light grey.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Replace all <literal>gtk_paint_*()</literal> calls with corresponding
- <literal>gtk_render_*()</literal> calls.
- </para>
- <para>
- The most distinctive changes are the use of #GtkStateFlags to
- represent the widget state and the lack of #GtkShadowType. Note
- that widget state is now passed implicitly via the context, so
- to render in a certain state, you have to temporarily set the
- state on the context, as in the following example:
- </para>
- <example>
- <title>Rendering with a specific state</title>
- <programlisting>
- gtk_style_context_save (context);
- gtk_style_context_set_state (context, GTK_STATE_FLAG_ACTIVE);
- gtk_render_check (context, cr, x, y, width, height);
- gtk_style_context_restore (context);
- </programlisting>
- </example>
- <para>
- For gtk_render_check() and gtk_render_option(), the @shadow_type
- parameter is replaced by the #GTK_STATE_FLAG_ACTIVE and
- #GTK_STATE_FLAG_INCONSISTENT state flags. For things such as
- pressed/unpressed button states, #GTK_STATE_FLAG_ACTIVE is used,
- and the CSS may style normal/active states differently to render
- outset/inset borders, respectively.
- </para>
- </listitem>
-
- <listitem>
- The various <literal>gtk_widget_modify_*()</literal> functions to
- override colors or fonts for individual widgets have been replaced
- by similar <literal>gtk_widget_override_*()</literal> functions.
- </listitem>
-
- <listitem>
- It is no longer necessary to call gtk_widget_style_attach(),
- gtk_style_attach(), gtk_style_detach() or gtk_widget_ensure_style().
- </listitem>
-
- <listitem>
- Replace all uses of xthickness/ythickness. #GtkStyleContext uses the
- CSS box model, and there are border-width/padding/margin properties to
- replace the different applications of X and Y thickness. Note that all
- of this is merely a guideline. Widgets may choose to follow it or not.
- </listitem>
- </orderedlist>
- </section>
-
- <section id="gtk-migrating-GtkStyleContext-parsing">
- <title>Parsing of custom resources</title>
- <para>
- As a consequence of the RC format going away, calling gtk_rc_parse() or
- gtk_rc_parse_string() won't have any effect on a widgets appearance.
- The way to replace these calls is using a custom #GtkStyleProvider,
- either for an individual widget through gtk_style_context_add_provider()
- or for all widgets on a screen through gtk_style_context_add_provider_for_screen().
- Typically, the provider will be a #GtkCssProvider, which parse CSS
- information from a file or from a string.
- </para>
- <example>
- <title>Using a custom GtkStyleProvider</title>
- <programlisting>
- GtkStyleContext *context;
- GtkCssProvider *provider;
-
- context = gtk_widget_get_style_context (widget);
- provider = gtk_css_provider_new ();
- gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (provider),
- ".frame1 {\n"
- " border-image: url('gradient1.png') 10 10 10 10 stretch;\n"
- "}\n", -1, NULL);
- gtk_style_context_add_provider (context,
- GTK_STYLE_PROVIDER (provider),
- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
- g_object_unref (provider);
- </programlisting>
- </example>
- <para>
- Notice that you can also get style information from custom resources
- by implementing the #GtkStyleProvider interface yourself. This is
- an advanced feature that should be rarely used.
- </para>
- </section>
-
- <section id="gtk-migrating-GtkStyleContext-bonus-points">
- <title>Bonus points</title>
-
- <para>
- There are some features in #GtkStyleContext that were not available in
- #GtkStyle, or were made available over time for certain widgets through
- extending the detail string in obscure ways. There is a lot more
- information available when rendering UI elements, and it is accessible
- in more uniform, less hacky ways. By going through this list you'll
- ensure your widget is a good citizen in a fully themable user interface.
- </para>
-
- <orderedlist>
- <listitem>
- If your widget renders a series of similar elements, such as tabs
- in a #GtkNotebook or rows/column in a #GtkTreeView, consider adding
- regions through gtk_style_context_add_region(). These regions can be
- referenced in CSS and the :nth-child pseudo-class may be used to match
- the elements depending on the flags passed.
-
- <example>
- <title>Theming widget regions</title>
- <programlisting>
- GtkNotebook tab {
- background-color: #f3329d;
- }
-
- GtkTreeView row::nth-child (even) {
- background-color: #dddddd;
- }
- </programlisting>
- </example>
- </listitem>
-
- <listitem>
- <para>
- If your container renders child widgets within different regions,
- make it implement #GtkContainer get_path_for_child(<!-- -->). This function
- lets containers assign a special #GtkWidgetPath to child widgets
- depending on their role/region. This is necessary to extend the
- concept above throughout the widget hierarchy.
- </para>
-
- <para>
- For example, a #GtkNotebook modifies the tab labels' #GtkWidgetPath
- so the "tab" region is added. This makes it possible to theme tab
- labels through:
- </para>
-
- <example>
- <title>Theming a widget within a parent container region</title>
- <programlisting>
- GtkNotebook tab GtkLabel {
- font: Sans 8;
- }
- </programlisting>
- </example>
-
- </listitem>
-
- <listitem>
- If you intend several visual elements to look interconnected,
- make sure you specify rendered elements' connection areas with
- gtk_style_context_set_junction_sides(). It is of course up to the
- theme to make use of this information or not.
- </listitem>
-
- <listitem>
- <para>
- #GtkStyleContext supports implicit animations on state changes for
- the most simple case out-of-the-box: widgets with a single animatable
- area, whose state is changed with gtk_widget_set_state_flags() or
- gtk_widget_unset_state_flags(). These functions trigger animated
- transitions for the affected state flags. Examples of widgets for
- which this kind of animation may be sufficient are #GtkButton or
- #GtkEntry.
- </para>
- <para>
- If your widget consists of more than a simple area, and these areas
- may be rendered with different states, make sure to mark the rendered
- areas with gtk_style_context_push_animatable_region() and
- gtk_style_context_pop_animatable_region().
- </para>
-
- <para>
- gtk_style_context_notify_state_change() may be used to trigger a
- transition for a given state. The region ID will determine the
- animatable region that is affected by this transition.
- </para>
- </listitem>
- </orderedlist>
- </section>
-</chapter>
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-]>
-<chapter id="gtk-migrating-checklist">
- <title>Migration Details Checklist</title>
-
- <para>
- This chapter includes a checklist of smaller things you need to do to
- ensure that your programs are good citizens in the GTK+ world. By
- paying attention to the points in the checklist, you ensure that
- many automatic features of GTK+ will work correctly in your
- program.
- </para>
-
- <section id="checklist-popup-menu">
- <title>Implement GtkWidget::popup_menu</title>
-
- <formalpara>
- <title>Why</title>
- <para>
- By handling this signal, you let widgets have
- context-sensitive menus that can be invoked with the standard
- key bindings.
- </para>
- </formalpara>
-
- <para>
- The #GtkWidget::popup-menu signal instructs the widget for which
- it is emitted to create a context-sensitive popup menu. By default,
- the <link linkend="gtk-bindings-install">key binding mechanism</link> is set to
- emit this signal when the
- <keycombo><keycap>Shift</keycap><keycap>F10</keycap></keycombo>
- or <keycap>Menu</keycap> keys are pressed while a widget has the
- focus. If a widget in your application shows a popup menu when
- you press a mouse button, you can make it work as well through
- the normal key binding mechanism in the following fahion:
- </para>
-
- <orderedlist>
- <listitem>
- <para>
- Write a function to create and show a popup menu. This
- function needs to know the button number and the event's
- time to pass them to gtk_menu_popup(). You can implement
- such a function like this:
- </para>
-
- <programlisting id="do_popup_menu">
-static void
-do_popup_menu (GtkWidget *my_widget, GdkEventButton *event)
-{
- GtkWidget *menu;
- int button, event_time;
-
- menu = gtk_menu_new (<!-- -->);
- g_signal_connect (menu, "deactivate",
- G_CALLBACK (gtk_widget_destroy), NULL);
-
- /* ... add menu items ... */
-
- if (event)
- {
- button = event->button;
- event_time = event->time;
- }
- else
- {
- button = 0;
- event_time = gtk_get_current_event_time (<!-- -->);
- }
-
- gtk_menu_attach_to_widget (GTK_MENU (menu), my_widget, NULL);
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
- button, event_time);
-}
- </programlisting>
- </listitem>
-
- <listitem>
- <para>
- In your #GtkWidget::button-press-event handler, call this function
- when you need to pop up a menu:
- </para>
-
- <programlisting>
-static gboolean
-my_widget_button_press_event_handler (GtkWidget *widget, GdkEventButton *event)
-{
- /* Ignore double-clicks and triple-clicks */
- if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
- event->type == GDK_BUTTON_PRESS)
- {
- do_popup_menu (widget, event);
- return TRUE;
- }
-
- return FALSE;
-}
- </programlisting>
- </listitem>
-
- <listitem>
- <para>
- Implement a handler for the #GtkWidget::popup-menu signal:
- </para>
-
- <programlisting>
-static gboolean
-my_widget_popup_menu_handler (GtkWidget *widget)
-{
- do_popup_menu (widget, NULL);
- return TRUE;
-}
- </programlisting>
- </listitem>
- </orderedlist>
-
- <note>
- <para>
- If you do not pass a positioning function to gtk_menu_popup(),
- it will show the menu at the mouse position by default. This
- is what you usually want when the menu is shown as a result of
- pressing a mouse button. However, if you press the
- <keycombo><keycap>Shift</keycap><keycap>F10</keycap></keycombo>
- or <keycap>Menu</keycap> keys while the widget is focused, the
- mouse cursor may not be near the widget at all. In the <link
- linkend="do_popup_menu">example above</link>, you may want to
- provide your own <link
- linkend="GtkMenuPositionFunc">menu-positioning function</link>
- in the case where the <parameter>event</parameter> is
- %NULL. This function should compute the desired position for
- a menu when it is invoked through the keyboard. For example,
- #GtkEntry aligns the top edge of its popup menu with the bottom
- edge of the entry.
- </para>
- </note>
-
- <note>
- <para>
- For the standard key bindings to work, your widget must be
- able to take the keyboard focus. In general, widgets should
- be fully usable through the keyboard and not just the mouse.
- The very first step of this is to ensure that your widget
- can receive focus, using gtk_widget_set_can_focus().
- </para>
- </note>
- </section>
-
- <section id="checklist-gdkeventexpose-region">
- <title>Use GdkEventExpose.region</title>
-
- <formalpara>
- <title>Why</title>
- <para>
- The <structfield>region</structfield> field of
- <structname>GdkEventExpose</structname> allows you to redraw
- less than the traditional <structfield>GdkEventRegion.area</structfield>.
- </para>
- </formalpara>
-
- <para>
- In early GTK+ versions, the <structname>GdkEventExpose</structname>
- structure only had an <structfield>area</structfield> field to
- let you determine the region that you needed to redraw. In current
- GTK+, this field still exists for compatibility and as a simple
- interface. However, there is also a <structfield>region</structfield>
- field which contains a fine-grained region. The
- <structfield>area</structfield> field is simply the bounding rectangle
- of the <structfield>region</structfield>.
- </para>
-
- <para>
- Widgets that are very expensive to re-render, such as an image
- editor, may prefer to use the
- <structfield>GdkEventExpose.region</structfield> field to paint
- as little as possible. Widgets that just use a few drawing
- primitives, such as labels and buttons, may prefer to use the
- traditional <structfield>GdkEventExpose.area</structfield> field
- for simplicity.
- </para>
-
- <para>
- Regions have an internal representation that is accessible as a
- list of rectangles. To turn the
- <structfield>GdkEventExpose.region</structfield> field into such
- a list, use gdk_region_get_rectangles():
- </para>
-
- <programlisting id="gdkregion-get-rectangles">
-static gboolean
-my_widget_expose_event_handler (GtkWidget *widget, GdkEventExpose *event)
-{
- GdkRectangle *rects;
- int n_rects;
- int i;
-
- gdk_region_get_rectangles (event->region, &rects, &n_rects);
-
- for (i = 0; i < n_rects; i++)
- {
- /* Repaint rectangle: (rects[i].x, rects[i].y),
- * (rects[i].width, rects[i].height)
- */
- }
-
- g_free (rects);
-
- return FALSE;
-}
- </programlisting>
- </section>
-
- <section id="checklist-modifiers">
- <title>Test for modifier keys correctly</title>
-
- <formalpara>
- <title>Why</title>
- <para>
- With gtk_accelerator_get_default_mod_mask() you can test for
- modifier keys reliably; this way your key event handlers will
- work correctly even if <keycap>NumLock</keycap> or
- <keycap>CapsLock</keycap> are activated.
- </para>
- </formalpara>
-
- <para>
- In a <structname>GdkEventKey</structname>, the
- <structfield>state</structfield> field is a bit mask which
- indicates the modifier state at the time the key was pressed.
- Modifiers are keys like <keycap>Control</keycap> and
- <keycap>NumLock</keycap>. When implementing a
- #GtkWidget::key-press-event handler, you should use
- gtk_accelerator_get_default_mod_mask() to
- test against modifier keys. This function returns a bit mask
- which encompasses all the modifiers which the user may be
- actively pressing, such as <keycap>Control</keycap>,
- <keycap>Shift</keycap>, and <keycap>Alt</keycap>, but ignores
- "innocuous" modifiers such as <keycap>NumLock</keycap> and
- <keycap>CapsLock</keycap>.
- </para>
-
- <para>
- Say you want to see if
- <keycombo><keycap>Control</keycap><keycap>F10</keycap></keycombo>
- was pressed. Doing a simple test like
- <literal>event->keysym == GDK_F10 &&
- event->state == GDK_CONTROL_MASK</literal> is not
- enough. If <keycap>CapsLock</keycap> is pressed, then
- <structfield>event->state</structfield> will be equal to
- <literal>GDK_CONTROL_MASK | GDK_LOCK_MASK</literal>, and the
- simple test will fail. By taking the logical-and of
- <structfield>event->state</structfield> and
- gtk_accelerator_get_default_mod_mask(), you
- can ignore the modifiers which are not actively pressed by the
- user at the same time as the base key.
- </para>
-
- <para>
- The following example correctly tests for
- <keycombo><keycap>Control</keycap><keycap>F10</keycap></keycombo>
- being pressed.
- </para>
-
- <programlisting id="default-mod-mask">
-static gboolean
-my_widget_key_press_event_handler (GtkWidget *widget, GdkEventKey *event)
-{
- GdkModifierType modifiers;
-
- modifiers = gtk_accelerator_get_default_mod_mask (<!-- -->);
-
- if (event->keysym == GDK_F10
- && (event->state & modifiers) == GDK_CONTROL_MASK)
- {
- g_print ("Control-F10 was pressed\n");
- return TRUE;
- }
-
- return FALSE;
-}
- </programlisting>
- </section>
-
- <section id="checklist-named-icons">
- <title>Use named icons</title>
-
- <formalpara>
- <title>Why</title>
- <para>
- Named icons automatically adapt to theme changes, giving your
- application a much more integrated appearance.
- </para>
- </formalpara>
-
- <para>
- Named icons can be used for window icons (see gtk_window_set_icon_name())
- and images (see gtk_image_set_from_icon_name()). You can also use named icons
- for drag-and-drop (see gtk_drag_source_set_icon_name()) and in treeview
- cells (see the #GtkCellRendererPixbuf:icon-name property).
- </para>
- </section>
-</chapter>
-
-<!--
-Local variables:
-mode: sgml
-sgml-parent-document: ("gtk-docs.sgml" "book" "part" "chapter")
-End:
--->
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-]>
-<chapter id="gtk-migrating-smclient-GtkApplication">
-
- <title>Migrating from EggSMClient to GtkApplication</title>
-
- <para>
- EggSMClient provides 'session management' support for applications.
- This means a number of things:
- <itemizedlist>
- <listitem>logout notification and negotiation</listitem>
- <listitem>application state saving</listitem>
- <listitem>restarting of applications with saved state</listitem>
- </itemizedlist>
- EggSMClient supports this functionality to varying degrees on
- Windows and OS X, as well as with XSMP and D-Bus based session
- managers in X11.
- </para>
-
- <para>
- Starting with GTK+ 3.4, #GtkApplication supports logout notification
- and negotiation similar to EggSMClient.
- </para>
- <table>
- <tgroup cols="2">
- <title>EggSMClient to GtkApplication</title>
- <thead>
- <row><entry>EggSMClient</entry><entry>GtkApplication</entry></row>
- </thead>
- <tbody>
- <row><entry>EggSMClient::quit-requested</entry><entry>instead of calling will_quit (FALSE,...) in response to this signal, install an inhibitor</entry></row>
- <row><entry>EggSMClient::quit</entry><entry>the #GApplication::shutdown signal</entry></row>
- <row><entry>EggSMClient::quit-cancelled</entry><entry>-</entry></row>
- <row><entry>egg_sm_client_will_quit</entry><entry>instead of calling will_quit (FALSE,...), install an inhibitor</entry></row>
- <row><entry>egg_sm_client_end_session</entry><entry>-</entry></row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- At this point, GtkApplication has no special support for state saving
- and restarting. Applications can use GSettings or GKeyFile and save as
- much state as they see fit in response to #GApplication::shutdown or
- whenever they consider appropriate.
- </para>
-</chapter>
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-]>
-<chapter id="gtk-migrating-unique-GtkApplication">
-
- <title>Migrating from libunique to GApplication or GtkApplication</title>
-
- <para>
- libunique offers 'unique application' support as well as ways to
- communicate with a running application instance. This is implemented
- in various ways, either using D-Bus, or socket-based communication.
- </para>
-
- <para>
- Starting with GLib 2.26, D-Bus support has been integrated into GIO
- in the form of GDBus, and #GApplication has been added to provide
- the same level of application support as libunique.
- </para>
-
- <example><title>A unique application</title>
- <para>Here is a simple application using libunique:
- <informalexample><programlisting>
-int
-main (int argc, char *argv[])
-{
- UniqueApp *app;
- GtkWidget *window;
-
- gtk_init (&argc, &argv);
-
- app = unique_app_new ("org.gtk.TestApplication", NULL);
-
- if (unique_app_is_running (app))
- {
- UniqueResponse response;
-
- response = unique_app_send_message (app, UNIQUE_ACTIVATE, NULL);
- g_object_unref (app);
-
- return response == UNIQUE_RESPONSE_OK ? 0 : 1;
- }
-
- window = create_my_window ();
-
- unique_app_watch_window (app, GTK_WINDOW (window));
-
- gtk_widget_show (window);
-
- gtk_main ();
-
- g_object_unref (app);
-
- return 0;
-}
-</programlisting></informalexample>
-The same application using GtkApplication:
-<informalexample><programlisting>
-static void
-activate (GtkApplication *app)
-{
- GList *list;
- GtkWidget *window;
-
- list = gtk_application_get_windows (app);
-
- if (list)
- {
- gtk_window_present (GTK_WINDOW (list->data));
- }
- else
- {
- window = create_my_window ();
- gtk_window_set_application (GTK_WINDOW (window), app);
- gtk_widget_show (window);
- }
-}
-
-int
-main (int argc, char *argv[])
-{
- GtkApplication *app;
- gint status;
-
- app = gtk_application_new ("org.gtk.TestApplication", 0);
- g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
-
- status = g_application_run (G_APPLICATION (app), argc, argv);
-
- g_object_unref (app);
-
- return status;
-}
-</programlisting></informalexample>
-</para>
-</example>
- <section><title>Uniqueness</title>
- <para>
- Instead of creating a UniqueApp with unique_app_new(<!-- -->), create
- a #GApplication with g_application_new() or a #GtkApplication
- with gtk_application_new(). The @name that was used with
- unique_app_new() is very likely usable as the @application_id for
- g_application_new() without any changes, and GtkApplication passes
- the <envar>DESKTOP_STARTUP_ID</envar> environment variable
- automatically.
- </para>
- <para>
- While libunique expects you to check for an already running instance
- yourself and activate it manually, GApplication handles all this on
- its own in g_application_run(). If you still need to find out if there
- is a running instance of your application, use
- g_application_get_is_remote() instead of unique_app_is_running().
- </para>
- </section>
-
- <section><title>Commands and Messages</title>
- <para>
- libunique lets you send messages with commands to a running
- instance using unique_app_send_message(<!-- -->). The commands can be either
- predefined or custom. Some of the predefined libunique commands have
- equivalents in GApplication. Instead of sending the UNIQUE_ACTIVATE
- command, call g_application_activate(), instead of sending the
- UNIQUE_OPEN command, call g_application_open(). The
- UNIQUE_NEW and UNIQUE_CLOSE and user-defined commands don't
- have direct replacement at this time.
- </para>
-
- <para>
- As a replacement for custom commands, GApplication implements the
- #GActionGroup interface and lets you add a group of actions with
- g_application_set_action_group(). The actions can then be invoked,
- either by using the D-Bus interface for #GAction directly, or by
- calling g_action_group_activate_action() from another instance of
- the GApplication. The #GApplication documentation contains an
- example for using GApplication with actions.
- </para>
-
- <para>
- For more complex needs, GApplication supports passing entire
- commandlines to the running instance.
- </para>
- </section>
-</chapter>